Backed out 8 changesets (bug 1616411) for webgl failures on test_2_conformance__textures__misc__texture-upload-size.html. CLOSED TREE

Backed out changeset 03dd88d53439 (bug 1616411)
Backed out changeset cfee2ce9405d (bug 1616411)
Backed out changeset 0a323c33506f (bug 1616411)
Backed out changeset 1a25353a07b0 (bug 1616411)
Backed out changeset dc64af52b5f8 (bug 1616411)
Backed out changeset 0f54b1b12105 (bug 1616411)
Backed out changeset 4dee3e753e8e (bug 1616411)
Backed out changeset 034a30a6b088 (bug 1616411)
This commit is contained in:
Csoregi Natalia 2020-04-16 05:43:16 +03:00
parent 352456ac8d
commit ea673441ce
50 changed files with 270 additions and 725 deletions

View File

@ -1233,7 +1233,6 @@ uint32_t nsImageLoadingContent::NaturalWidth() {
int32_t size = 0;
if (image) {
if (image->GetOrientation().SwapsWidthAndHeight() &&
!image->HandledOrientation() &&
StaticPrefs::image_honor_orientation_metadata_natural_size()) {
Unused << image->GetHeight(&size);
} else {
@ -1252,7 +1251,6 @@ uint32_t nsImageLoadingContent::NaturalHeight() {
int32_t size = 0;
if (image) {
if (image->GetOrientation().SwapsWidthAndHeight() &&
!image->HandledOrientation() &&
StaticPrefs::image_honor_orientation_metadata_natural_size()) {
Unused << image->GetWidth(&size);
} else {

View File

@ -44,7 +44,7 @@ skip-if(Android) == 649134-2.html 649134-2-ref.html
# (Fuzzy necessary due to pixel-wise comparison of different JPEGs.
# The vast majority of the fuzziness comes from Linux and WinXP.)
pref(layout.css.image-orientation.initial-from-image,true) fuzzy(0-2,0-830) == bug917595-iframe-1.html bug917595-1-ref.html
fuzzy(0-3,0-640) fuzzy-if(skiaContent,0-3,0-7544) fuzzy-if(webrender&&!geckoview,2-3,52-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
fuzzy(0-3,0-640) fuzzy-if(skiaContent,0-3,0-7544) fuzzy-if(webrender&&!geckoview,2-3,3092-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869
# Test support for SVG-as-image in <picture> elements.
== bug1106522-1.html bug1106522-ref.html

View File

@ -112,9 +112,6 @@ Maybe<AspectRatio> DynamicImage::GetIntrinsicRatio() {
NS_IMETHODIMP_(Orientation)
DynamicImage::GetOrientation() { return Orientation(); }
NS_IMETHODIMP_(bool)
DynamicImage::HandledOrientation() { return false; }
NS_IMETHODIMP
DynamicImage::GetType(uint16_t* aType) {
*aType = imgIContainer::TYPE_RASTER;

View File

@ -65,8 +65,7 @@ void IDecodingTask::NotifyProgress(NotNull<RasterImage*> aImage,
// calls we make off-main-thread and the notifications that RasterImage
// actually receives, which would cause bugs.
Progress progress = aDecoder->TakeProgress();
UnorientedIntRect invalidRect =
UnorientedIntRect::FromUnknownRect(aDecoder->TakeInvalidRect());
IntRect invalidRect = aDecoder->TakeInvalidRect();
Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();
@ -101,8 +100,7 @@ void IDecodingTask::NotifyDecodeComplete(NotNull<RasterImage*> aImage,
ImageMetadata metadata = aDecoder->GetImageMetadata();
DecoderTelemetry telemetry = aDecoder->Telemetry();
Progress progress = aDecoder->TakeProgress();
UnorientedIntRect invalidRect =
UnorientedIntRect::FromUnknownRect(aDecoder->TakeInvalidRect());
IntRect invalidRect = aDecoder->TakeInvalidRect();
Maybe<uint32_t> frameCount = aDecoder->TakeCompleteFrameCount();
DecoderFlags decoderFlags = aDecoder->GetDecoderFlags();
SurfaceFlags surfaceFlags = aDecoder->GetSurfaceFlags();

View File

@ -71,14 +71,6 @@ already_AddRefed<imgIContainer> ImageOps::Orient(imgIContainer* aImage,
return orientedImage.forget();
}
/* static */
already_AddRefed<imgIContainer> ImageOps::Unorient(imgIContainer* aImage) {
Orientation orientation = aImage->GetOrientation().Reversed();
nsCOMPtr<imgIContainer> orientedImage =
new OrientedImage(static_cast<Image*>(aImage), orientation);
return orientedImage.forget();
}
/* static */
already_AddRefed<imgIContainer> ImageOps::CreateFromDrawable(
gfxDrawable* aDrawable) {

View File

@ -79,15 +79,6 @@ class ImageOps {
static already_AddRefed<imgIContainer> Orient(imgIContainer* aImage,
Orientation aOrientation);
/**
* Creates a version of an existing image which undoes any rotation and/or
* flipping that it has automatically handled.
*
* This only undoes the effect of a RasterImage's automatic orientation
* handling.
*/
static already_AddRefed<imgIContainer> Unorient(imgIContainer* aImage);
/**
* Creates an image from a gfxDrawable.
*

View File

@ -135,9 +135,6 @@ nsresult ImageWrapper::GetHotspotY(int32_t* aY) {
NS_IMETHODIMP_(Orientation)
ImageWrapper::GetOrientation() { return mInnerImage->GetOrientation(); }
NS_IMETHODIMP_(bool)
ImageWrapper::HandledOrientation() { return mInnerImage->HandledOrientation(); }
NS_IMETHODIMP
ImageWrapper::GetType(uint16_t* aType) { return mInnerImage->GetType(aType); }

View File

@ -19,19 +19,11 @@ enum class Flip : uint8_t { Unflipped, Horizontal };
* A struct that describes an image's orientation as a rotation optionally
* followed by a reflection. This may be used to be indicate an image's inherent
* orientation or a desired orientation for the image.
*
* When flipFirst = true, this indicates that the reflection is applied before
* the rotation. (This is used by OrientedImage to represent the inverse of an
* underlying image's Orientation.)
*/
struct Orientation {
explicit Orientation(Angle aRotation = Angle::D0,
Flip aFlip = Flip::Unflipped, bool aFlipFirst = false)
: rotation(aRotation), flip(aFlip), flipFirst(aFlipFirst) {}
Orientation Reversed() const {
return Orientation(InvertAngle(rotation), flip, !flipFirst);
}
Flip mFlip = Flip::Unflipped)
: rotation(aRotation), flip(mFlip) {}
bool IsIdentity() const {
return (rotation == Angle::D0) && (flip == Flip::Unflipped);
@ -42,28 +34,15 @@ struct Orientation {
}
bool operator==(const Orientation& aOther) const {
return rotation == aOther.rotation && flip == aOther.flip &&
flipFirst == aOther.flipFirst;
return (rotation == aOther.rotation) && (flip == aOther.flip);
}
bool operator!=(const Orientation& aOther) const {
return !(*this == aOther);
}
static Angle InvertAngle(Angle aAngle) {
switch (aAngle) {
case Angle::D90:
return Angle::D270;
case Angle::D270:
return Angle::D90;
default:
return aAngle;
}
}
Angle rotation;
Flip flip;
bool flipFirst;
};
} // namespace image

View File

@ -75,34 +75,37 @@ Maybe<AspectRatio> OrientedImage::GetIntrinsicRatio() {
return ratio;
}
already_AddRefed<SourceSurface> OrientedImage::OrientSurface(
Orientation aOrientation, SourceSurface* aSurface) {
MOZ_ASSERT(aSurface);
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
nsresult rv;
// If the image does not require any re-orientation, return aSurface itself.
if (aOrientation.IsIdentity()) {
return do_AddRef(aSurface);
if (mOrientation.IsIdentity()) {
return InnerImage()->GetFrame(aWhichFrame, aFlags);
}
// Determine the size of the new surface.
nsIntSize originalSize = aSurface->GetSize();
nsIntSize targetSize = originalSize;
if (aOrientation.SwapsWidthAndHeight()) {
swap(targetSize.width, targetSize.height);
}
// Get the underlying dimensions.
IntSize size;
rv = InnerImage()->GetWidth(&size.width);
NS_ENSURE_SUCCESS(rv, nullptr);
rv = InnerImage()->GetHeight(&size.height);
NS_ENSURE_SUCCESS(rv, nullptr);
RefPtr<SourceSurface> innerSurface =
InnerImage()->GetFrame(aWhichFrame, aFlags);
NS_ENSURE_TRUE(innerSurface, nullptr);
// Create our drawable.
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(aSurface, originalSize);
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(innerSurface, size);
// Determine an appropriate format for the surface.
gfx::SurfaceFormat surfaceFormat = IsOpaque(aSurface->GetFormat())
gfx::SurfaceFormat surfaceFormat = IsOpaque(innerSurface->GetFormat())
? gfx::SurfaceFormat::OS_RGBX
: gfx::SurfaceFormat::OS_RGBA;
// Create the new surface to draw into.
// Create a surface to draw into.
RefPtr<DrawTarget> target =
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
targetSize, surfaceFormat);
size, surfaceFormat);
if (!target || !target->IsValid()) {
NS_ERROR("Could not create a DrawTarget");
return nullptr;
@ -111,25 +114,14 @@ already_AddRefed<SourceSurface> OrientedImage::OrientSurface(
// Draw.
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(target);
MOZ_ASSERT(ctx); // already checked the draw target above
ctx->Multiply(OrientationMatrix(aOrientation, originalSize));
gfxUtils::DrawPixelSnapped(ctx, drawable, SizeDouble(originalSize),
ImageRegion::Create(originalSize), surfaceFormat,
ctx->Multiply(OrientationMatrix(size));
gfxUtils::DrawPixelSnapped(ctx, drawable, SizeDouble(size),
ImageRegion::Create(size), surfaceFormat,
SamplingFilter::LINEAR);
return target->Snapshot();
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
// Get a SourceSurface for the inner image then orient it according to
// mOrientation.
RefPtr<SourceSurface> innerSurface =
InnerImage()->GetFrame(aWhichFrame, aFlags);
NS_ENSURE_TRUE(innerSurface, nullptr);
return OrientSurface(mOrientation, innerSurface);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
OrientedImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
uint32_t aFlags) {
@ -226,27 +218,44 @@ struct MatrixBuilder {
bool mInvert;
};
gfxMatrix OrientedImage::OrientationMatrix(Orientation aOrientation,
const nsIntSize& aSize,
/*
* OrientationMatrix() computes a matrix that applies the rotation and
* reflection specified by mOrientation, or that matrix's inverse if aInvert is
* true.
*
* @param aSize The scaled size of the inner image. (When outside code specifies
* the scaled size, as with imgIContainer::Draw and its aSize
* parameter, it's necessary to swap the width and height if
* mOrientation.SwapsWidthAndHeight() is true.)
* @param aInvert If true, compute the inverse of the orientation matrix. Prefer
* this approach to OrientationMatrix(..).Invert(), because it's
* more numerically accurate.
*/
gfxMatrix OrientedImage::OrientationMatrix(const nsIntSize& aSize,
bool aInvert /* = false */) {
MatrixBuilder builder(aInvert);
// Apply reflection, if present. (For a regular, non-flipFirst reflection,
// this logically happens second, but we apply it first because these
// transformations are all premultiplied.) A translation is necessary to place
// the image back in the first quadrant.
if (aOrientation.flip == Flip::Horizontal && !aOrientation.flipFirst) {
if (aOrientation.SwapsWidthAndHeight()) {
builder.Translate(gfxPoint(aSize.height, 0));
} else {
builder.Translate(gfxPoint(aSize.width, 0));
}
builder.Scale(-1.0, 1.0);
// Apply reflection, if present. (This logically happens second, but we
// apply it first because these transformations are all premultiplied.) A
// translation is necessary to place the image back in the first quadrant.
switch (mOrientation.flip) {
case Flip::Unflipped:
break;
case Flip::Horizontal:
if (mOrientation.SwapsWidthAndHeight()) {
builder.Translate(gfxPoint(aSize.height, 0));
} else {
builder.Translate(gfxPoint(aSize.width, 0));
}
builder.Scale(-1.0, 1.0);
break;
default:
MOZ_ASSERT(false, "Invalid flip value");
}
// Apply rotation, if present. Again, a translation is used to place the
// image back in the first quadrant.
switch (aOrientation.rotation) {
switch (mOrientation.rotation) {
case Angle::D0:
break;
case Angle::D90:
@ -265,12 +274,6 @@ gfxMatrix OrientedImage::OrientationMatrix(Orientation aOrientation,
MOZ_ASSERT(false, "Invalid rotation value");
}
// Apply a flipFirst reflection.
if (aOrientation.flip == Flip::Horizontal && aOrientation.flipFirst) {
builder.Translate(gfxPoint(aSize.width, 0.0));
builder.Scale(-1.0, 1.0);
}
return builder.Build();
}

View File

@ -63,39 +63,13 @@ class OrientedImage : public ImageWrapper {
gfx::SamplingFilter aSamplingFilter,
uint32_t aFlags) override;
/**
* Computes a matrix that applies the rotation and reflection specified by
* aOrientation, or that matrix's inverse if aInvert is true.
*
* @param aSize The scaled size of the inner image. (When outside code
* specifies the scaled size, as with imgIContainer::Draw and its aSize
* parameter, it's necessary to swap the width and height if
* mOrientation.SwapsWidthAndHeight() is true.)
*
* @param aInvert If true, compute the inverse of the orientation matrix.
* Prefer this approach to OrientationMatrix(..).Invert(), because it's more
* numerically accurate.
*/
static gfxMatrix OrientationMatrix(Orientation aOrientation,
const nsIntSize& aSize,
bool aInvert = false);
/**
* Returns a SourceSurface that is the result of rotating and flipping
* aSurface according to aOrientation.
*/
static already_AddRefed<SourceSurface> OrientSurface(Orientation aOrientation,
SourceSurface* aSurface);
protected:
OrientedImage(Image* aImage, Orientation aOrientation)
: ImageWrapper(aImage), mOrientation(aOrientation) {}
virtual ~OrientedImage() {}
gfxMatrix OrientationMatrix(const nsIntSize& aSize, bool aInvert = false) {
return OrientationMatrix(mOrientation, aSize, aInvert);
}
gfxMatrix OrientationMatrix(const nsIntSize& aSize, bool aInvert = false);
private:
Orientation mOrientation;

View File

@ -21,7 +21,6 @@
#include "ImageRegion.h"
#include "Layers.h"
#include "LookupResult.h"
#include "OrientedImage.h"
#include "SourceBuffer.h"
#include "SurfaceCache.h"
#include "gfx2DGlue.h"
@ -87,8 +86,7 @@ RasterImage::RasterImage(nsIURI* aURI /* = nullptr */)
mHasBeenDecoded(false),
mPendingAnimation(false),
mAnimationFinished(false),
mWantFullDecode(false),
mHandledOrientation(StaticPrefs::image_honor_orientation_metadata()) {
mWantFullDecode(false) {
}
//******************************************************************************
@ -175,8 +173,7 @@ RasterImage::RequestRefresh(const TimeStamp& aTime) {
mFramesNotified++;
#endif
auto dirtyRect = UnorientedIntRect::FromUnknownRect(res.mDirtyRect);
NotifyProgress(NoProgress, dirtyRect);
NotifyProgress(NoProgress, res.mDirtyRect);
}
if (res.mAnimationFinished) {
@ -219,14 +216,11 @@ nsresult RasterImage::GetNativeSizes(nsTArray<IntSize>& aNativeSizes) const {
return NS_ERROR_FAILURE;
}
aNativeSizes.Clear();
if (mNativeSizes.IsEmpty()) {
aNativeSizes.AppendElement(mSize.ToUnknownSize());
aNativeSizes.Clear();
aNativeSizes.AppendElement(mSize);
} else {
for (const auto& size : mNativeSizes) {
aNativeSizes.AppendElement(size.ToUnknownSize());
}
aNativeSizes = mNativeSizes;
}
return NS_OK;
@ -269,9 +263,6 @@ Maybe<AspectRatio> RasterImage::GetIntrinsicRatio() {
NS_IMETHODIMP_(Orientation)
RasterImage::GetOrientation() { return mOrientation; }
NS_IMETHODIMP_(bool)
RasterImage::HandledOrientation() { return mHandledOrientation; }
//******************************************************************************
NS_IMETHODIMP
RasterImage::GetType(uint16_t* aType) {
@ -289,7 +280,7 @@ RasterImage::GetProducerId(uint32_t* aId) {
return NS_OK;
}
LookupResult RasterImage::LookupFrameInternal(const UnorientedIntSize& aSize,
LookupResult RasterImage::LookupFrameInternal(const IntSize& aSize,
uint32_t aFlags,
PlaybackType aPlaybackType,
bool aMarkUsed) {
@ -308,21 +299,17 @@ LookupResult RasterImage::LookupFrameInternal(const UnorientedIntSize& aSize,
if ((aFlags & FLAG_SYNC_DECODE) || !(aFlags & FLAG_HIGH_QUALITY_SCALING)) {
return SurfaceCache::Lookup(
ImageKey(this),
RasterSurfaceKey(aSize.ToUnknownSize(), surfaceFlags,
PlaybackType::eStatic),
RasterSurfaceKey(aSize, surfaceFlags, PlaybackType::eStatic),
aMarkUsed);
}
// We'll return the best match we can find to the requested frame.
return SurfaceCache::LookupBestMatch(
ImageKey(this),
RasterSurfaceKey(aSize.ToUnknownSize(), surfaceFlags,
PlaybackType::eStatic),
aMarkUsed);
RasterSurfaceKey(aSize, surfaceFlags, PlaybackType::eStatic), aMarkUsed);
}
LookupResult RasterImage::LookupFrame(const UnorientedIntSize& aSize,
uint32_t aFlags,
LookupResult RasterImage::LookupFrame(const IntSize& aSize, uint32_t aFlags,
PlaybackType aPlaybackType,
bool aMarkUsed) {
MOZ_ASSERT(NS_IsMainThread());
@ -333,8 +320,8 @@ LookupResult RasterImage::LookupFrame(const UnorientedIntSize& aSize,
aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
}
UnorientedIntSize requestedSize =
CanDownscaleDuringDecode(aSize, aFlags) ? aSize : ToUnoriented(mSize);
IntSize requestedSize =
CanDownscaleDuringDecode(aSize, aFlags) ? aSize : mSize;
if (requestedSize.IsEmpty()) {
// Can't decode to a surface of zero size.
return LookupResult(MatchType::NOT_FOUND);
@ -366,8 +353,7 @@ LookupResult RasterImage::LookupFrame(const UnorientedIntSize& aSize,
// decode at. This should only happen if we accept substitutions.
if (!result.SuggestedSize().IsEmpty()) {
MOZ_ASSERT(!syncDecode && (aFlags & FLAG_HIGH_QUALITY_SCALING));
requestedSize =
UnorientedIntSize::FromUnknownSize(result.SuggestedSize());
requestedSize = result.SuggestedSize();
}
bool ranSync = Decode(requestedSize, aFlags, aPlaybackType);
@ -445,11 +431,9 @@ RasterImage::WillDrawOpaqueNow() {
return false;
}
auto size = ToUnoriented(mSize);
LookupResult result = SurfaceCache::LookupBestMatch(
ImageKey(this),
RasterSurfaceKey(size.ToUnknownSize(), DefaultSurfaceFlags(),
PlaybackType::eStatic),
RasterSurfaceKey(mSize, DefaultSurfaceFlags(), PlaybackType::eStatic),
/* aMarkUsed = */ false);
MatchType matchType = result.Type();
if (matchType == MatchType::NOT_FOUND || matchType == MatchType::PENDING ||
@ -487,13 +471,9 @@ void RasterImage::OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded) {
if (aAnimatedFramesDiscarded && mAnimationState) {
MOZ_ASSERT(StaticPrefs::image_mem_animated_discardable_AtStartup());
ReleaseImageContainer();
auto size = ToUnoriented(mSize);
IntRect rect = mAnimationState->UpdateState(mAnimationFinished, this,
size.ToUnknownSize());
auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
NotifyProgress(NoProgress, dirtyRect);
gfx::IntRect rect =
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
NotifyProgress(NoProgress, rect);
}
if (mProgressTracker) {
@ -549,7 +529,7 @@ RasterImage::GetFirstFrameDelay() {
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
return GetFrameAtSize(mSize.ToUnknownSize(), aWhichFrame, aFlags);
return GetFrameAtSize(mSize, aWhichFrame, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
@ -569,8 +549,6 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
uint32_t aWhichFrame, uint32_t aFlags) {
MOZ_ASSERT(aWhichFrame <= FRAME_MAX_VALUE);
auto size = OrientedIntSize::FromUnknownSize(aSize);
if (aSize.IsEmpty() || aWhichFrame > FRAME_MAX_VALUE) {
return MakeTuple(ImgDrawResult::BAD_ARGS, aSize, RefPtr<SourceSurface>());
}
@ -582,85 +560,70 @@ RasterImage::GetFrameInternal(const IntSize& aSize,
// Get the frame. If it's not there, it's probably the caller's fault for
// not waiting for the data to be loaded from the network or not passing
// FLAG_SYNC_DECODE.
LookupResult result =
LookupFrame(ToUnoriented(size), aFlags, ToPlaybackType(aWhichFrame),
/* aMarkUsed = */ true);
auto resultSuggestedSize =
UnorientedIntSize::FromUnknownSize(result.SuggestedSize());
LookupResult result = LookupFrame(aSize, aFlags, ToPlaybackType(aWhichFrame),
/* aMarkUsed = */ true);
// The surface cache may have suggested we use a different size than the
// given size in the future. This may or may not be accompanied by an
// actual surface, depending on what it has in its cache.
OrientedIntSize suggestedSize = ToOriented(resultSuggestedSize);
if (suggestedSize.IsEmpty()) {
suggestedSize = size;
}
IntSize suggestedSize =
result.SuggestedSize().IsEmpty() ? aSize : result.SuggestedSize();
MOZ_ASSERT_IF(result.Type() == MatchType::SUBSTITUTE_BECAUSE_BEST,
suggestedSize != size);
suggestedSize != aSize);
if (!result) {
// The OS threw this frame away and we couldn't redecode it.
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR,
suggestedSize.ToUnknownSize(), RefPtr<SourceSurface>());
return MakeTuple(ImgDrawResult::TEMPORARY_ERROR, suggestedSize,
RefPtr<SourceSurface>());
}
RefPtr<SourceSurface> surface = result.Surface()->GetSourceSurface();
// If this RasterImage requires orientation, we must return a newly created
// surface with the oriented image instead of returning the frame's surface
// directly.
surface = OrientedImage::OrientSurface(UsedOrientation(), surface);
if (!result.Surface()->IsFinished()) {
return MakeTuple(ImgDrawResult::INCOMPLETE, suggestedSize.ToUnknownSize(),
return MakeTuple(ImgDrawResult::INCOMPLETE, suggestedSize,
std::move(surface));
}
return MakeTuple(ImgDrawResult::SUCCESS, suggestedSize.ToUnknownSize(),
std::move(surface));
return MakeTuple(ImgDrawResult::SUCCESS, suggestedSize, std::move(surface));
}
Tuple<ImgDrawResult, IntSize> RasterImage::GetImageContainerSize(
LayerManager* aManager, const IntSize& aRequestedSize, uint32_t aFlags) {
LayerManager* aManager, const IntSize& aSize, uint32_t aFlags) {
if (!mHasSize) {
return MakeTuple(ImgDrawResult::NOT_READY, IntSize(0, 0));
}
if (aRequestedSize.IsEmpty()) {
if (aSize.IsEmpty()) {
return MakeTuple(ImgDrawResult::BAD_ARGS, IntSize(0, 0));
}
// We check the minimum size because while we support downscaling, we do not
// support upscaling. If aRequestedSize > mSize, we will never give a larger
// surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
// we still want to use image containers if aRequestedSize <= maxTextureSize.
// support upscaling. If aSize > mSize, we will never give a larger surface
// than mSize. If mSize > aSize, and mSize > maxTextureSize, we still want to
// use image containers if aSize <= maxTextureSize.
int32_t maxTextureSize = aManager->GetMaxTextureSize();
if (min(mSize.width, aRequestedSize.width) > maxTextureSize ||
min(mSize.height, aRequestedSize.height) > maxTextureSize) {
if (min(mSize.width, aSize.width) > maxTextureSize ||
min(mSize.height, aSize.height) > maxTextureSize) {
return MakeTuple(ImgDrawResult::NOT_SUPPORTED, IntSize(0, 0));
}
auto requestedSize = OrientedIntSize::FromUnknownSize(aRequestedSize);
if (!CanDownscaleDuringDecode(ToUnoriented(requestedSize), aFlags)) {
return MakeTuple(ImgDrawResult::SUCCESS, mSize.ToUnknownSize());
if (!CanDownscaleDuringDecode(aSize, aFlags)) {
return MakeTuple(ImgDrawResult::SUCCESS, mSize);
}
return MakeTuple(ImgDrawResult::SUCCESS, aRequestedSize);
return MakeTuple(ImgDrawResult::SUCCESS, aSize);
}
NS_IMETHODIMP_(bool)
RasterImage::IsImageContainerAvailable(LayerManager* aManager,
uint32_t aFlags) {
return IsImageContainerAvailableAtSize(aManager, mSize.ToUnknownSize(),
aFlags);
return IsImageContainerAvailableAtSize(aManager, mSize, aFlags);
}
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags) {
RefPtr<ImageContainer> container;
ImgDrawResult drawResult =
GetImageContainerImpl(aManager, mSize.ToUnknownSize(), Nothing(), aFlags,
getter_AddRefs(container));
ImgDrawResult drawResult = GetImageContainerImpl(
aManager, mSize, Nothing(), aFlags, getter_AddRefs(container));
// We silence the unused warning here because anything that needs the draw
// result should be using GetImageContainerAtSize, not GetImageContainer.
@ -670,16 +633,16 @@ RasterImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags) {
NS_IMETHODIMP_(bool)
RasterImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
const IntSize& aRequestedSize,
const IntSize& aSize,
uint32_t aFlags) {
// We check the minimum size because while we support downscaling, we do not
// support upscaling. If aRequestedSize > mSize, we will never give a larger
// surface than mSize. If mSize > aRequestedSize, and mSize > maxTextureSize,
// we still want to use image containers if aRequestedSize <= maxTextureSize.
// support upscaling. If aSize > mSize, we will never give a larger surface
// than mSize. If mSize > aSize, and mSize > maxTextureSize, we still want to
// use image containers if aSize <= maxTextureSize.
int32_t maxTextureSize = aManager->GetMaxTextureSize();
if (!mHasSize || aRequestedSize.IsEmpty() ||
min(mSize.width, aRequestedSize.width) > maxTextureSize ||
min(mSize.height, aRequestedSize.height) > maxTextureSize) {
if (!mHasSize || aSize.IsEmpty() ||
min(mSize.width, aSize.width) > maxTextureSize ||
min(mSize.height, aSize.height) > maxTextureSize) {
return false;
}
@ -720,8 +683,8 @@ bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
}
if (aMetadata.HasSize()) {
auto metadataSize = UnorientedIntSize::FromUnknownSize(aMetadata.GetSize());
if (metadataSize.width < 0 || metadataSize.height < 0) {
IntSize size = aMetadata.GetSize();
if (size.width < 0 || size.height < 0) {
NS_WARNING("Image has negative intrinsic size");
DoError();
return true;
@ -731,8 +694,7 @@ bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
Orientation orientation = aMetadata.GetOrientation();
// If we already have a size, check the new size against the old one.
if (mHasSize &&
(metadataSize != ToUnoriented(mSize) || orientation != mOrientation)) {
if (mHasSize && (size != mSize || orientation != mOrientation)) {
NS_WARNING(
"Image changed size or orientation on redecode! "
"This should not happen!");
@ -741,21 +703,16 @@ bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
}
// Set the size and flag that we have it.
mSize = size;
mOrientation = orientation;
mSize = ToOriented(metadataSize);
mNativeSizes.Clear();
for (const auto& nativeSize : aMetadata.GetNativeSizes()) {
mNativeSizes.AppendElement(
ToOriented(UnorientedIntSize::FromUnknownSize(nativeSize)));
}
mNativeSizes = aMetadata.GetNativeSizes();
mHasSize = true;
}
if (mHasSize && aMetadata.HasAnimation() && !mAnimationState) {
// We're becoming animated, so initialize animation stuff.
mAnimationState.emplace(mAnimationMode);
mFrameAnimator =
MakeUnique<FrameAnimator>(this, ToUnoriented(mSize).ToUnknownSize());
mFrameAnimator = MakeUnique<FrameAnimator>(this, mSize);
if (!StaticPrefs::image_mem_animated_discardable_AtStartup()) {
// We don't support discarding animated images (See bug 414259).
@ -786,12 +743,6 @@ bool RasterImage::SetMetadata(const ImageMetadata& aMetadata,
}
if (aMetadata.HasHotspot()) {
// NOTE(heycam): We shouldn't have any image formats that support both
// orientation and hotspots, so we assert that rather than add code
// to orient the hotspot point correctly.
MOZ_ASSERT(UsedOrientation().IsIdentity(),
"Would need to orient hotspot point");
auto hotspot = aMetadata.GetHotspot();
mHotspot.x = std::max(std::min(hotspot.x, mSize.width - 1), 0);
mHotspot.y = std::max(std::min(hotspot.y, mSize.height - 1), 0);
@ -878,8 +829,7 @@ RasterImage::ResetAnimation() {
MOZ_ASSERT(mFrameAnimator, "Should have FrameAnimator");
mFrameAnimator->ResetAnimation(*mAnimationState);
IntRect area = mAnimationState->FirstFrameRefreshArea();
NotifyProgress(NoProgress, UnorientedIntRect::FromUnknownRect(area));
NotifyProgress(NoProgress, mAnimationState->FirstFrameRefreshArea());
// Start the animation again. It may not have been running before, if
// mAnimationFinished was true before entering this function.
@ -909,10 +859,6 @@ RasterImage::GetFrameIndex(uint32_t aWhichFrame) {
NS_IMETHODIMP_(IntRect)
RasterImage::GetImageSpaceInvalidationRect(const IntRect& aRect) {
// Note that we do not transform aRect into an UnorientedIntRect, since
// RasterImage::NotifyProgress notifies all consumers of the image using
// OrientedIntRect values. (This is unlike OrientedImage, which notifies
// using inner image coordinates.)
return aRect;
}
@ -1039,13 +985,9 @@ void RasterImage::Discard() {
if (mAnimationState) {
ReleaseImageContainer();
auto size = ToUnoriented(mSize);
IntRect rect = mAnimationState->UpdateState(mAnimationFinished, this,
size.ToUnknownSize());
auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
NotifyProgress(NoProgress, dirtyRect);
gfx::IntRect rect =
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
NotifyProgress(NoProgress, rect);
}
// Notify that we discarded.
@ -1074,7 +1016,7 @@ RasterImage::StartDecoding(uint32_t aFlags, uint32_t aWhichFrame) {
uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
FLAG_HIGH_QUALITY_SCALING;
return RequestDecodeForSize(mSize.ToUnknownSize(), flags, aWhichFrame);
return RequestDecodeForSize(mSize, flags, aWhichFrame);
}
bool RasterImage::StartDecodingWithResult(uint32_t aFlags,
@ -1091,7 +1033,7 @@ bool RasterImage::StartDecodingWithResult(uint32_t aFlags,
uint32_t flags = (aFlags & FLAG_ASYNC_NOTIFY) | FLAG_SYNC_DECODE_IF_FAST |
FLAG_HIGH_QUALITY_SCALING;
DrawableSurface surface =
RequestDecodeForSizeInternal(ToUnoriented(mSize), flags, aWhichFrame);
RequestDecodeForSizeInternal(mSize, flags, aWhichFrame);
return surface && surface->IsFinished();
}
@ -1105,7 +1047,7 @@ bool RasterImage::RequestDecodeWithResult(uint32_t aFlags,
uint32_t flags = aFlags | FLAG_ASYNC_NOTIFY;
DrawableSurface surface =
RequestDecodeForSizeInternal(ToUnoriented(mSize), flags, aWhichFrame);
RequestDecodeForSizeInternal(mSize, flags, aWhichFrame);
return surface && surface->IsFinished();
}
@ -1118,15 +1060,13 @@ RasterImage::RequestDecodeForSize(const IntSize& aSize, uint32_t aFlags,
return NS_ERROR_FAILURE;
}
RequestDecodeForSizeInternal(
ToUnoriented(OrientedIntSize::FromUnknownSize(aSize)), aFlags,
aWhichFrame);
RequestDecodeForSizeInternal(aSize, aFlags, aWhichFrame);
return NS_OK;
}
DrawableSurface RasterImage::RequestDecodeForSizeInternal(
const UnorientedIntSize& aSize, uint32_t aFlags, uint32_t aWhichFrame) {
const IntSize& aSize, uint32_t aFlags, uint32_t aWhichFrame) {
MOZ_ASSERT(NS_IsMainThread());
if (aWhichFrame > FRAME_MAX_VALUE) {
@ -1179,7 +1119,7 @@ static bool LaunchDecodingTask(IDecodingTask* aTask, RasterImage* aImage,
return false;
}
bool RasterImage::Decode(const UnorientedIntSize& aSize, uint32_t aFlags,
bool RasterImage::Decode(const IntSize& aSize, uint32_t aFlags,
PlaybackType aPlaybackType) {
MOZ_ASSERT(NS_IsMainThread());
@ -1234,13 +1174,11 @@ bool RasterImage::Decode(const UnorientedIntSize& aSize, uint32_t aFlags,
if (animated) {
size_t currentFrame = mAnimationState->GetCurrentAnimationFrameIndex();
rv = DecoderFactory::CreateAnimationDecoder(
mDecoderType, WrapNotNull(this), mSourceBuffer,
ToUnoriented(mSize).ToUnknownSize(), decoderFlags, surfaceFlags,
currentFrame, getter_AddRefs(task));
mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, decoderFlags,
surfaceFlags, currentFrame, getter_AddRefs(task));
} else {
rv = DecoderFactory::CreateDecoder(
mDecoderType, WrapNotNull(this), mSourceBuffer,
ToUnoriented(mSize).ToUnknownSize(), aSize.ToUnknownSize(),
mDecoderType, WrapNotNull(this), mSourceBuffer, mSize, aSize,
decoderFlags, surfaceFlags, getter_AddRefs(task));
}
@ -1257,11 +1195,9 @@ bool RasterImage::Decode(const UnorientedIntSize& aSize, uint32_t aFlags,
// async notifications. Any potential invalidation here will be sent when
// RequestRefresh is called, or NotifyDecodeComplete.
#ifdef DEBUG
IntRect rect =
gfx::IntRect rect =
#endif
mAnimationState->UpdateState(mAnimationFinished, this,
ToUnoriented(mSize).ToUnknownSize(),
false);
mAnimationState->UpdateState(mAnimationFinished, this, mSize, false);
MOZ_ASSERT(rect.IsEmpty());
}
@ -1300,7 +1236,7 @@ RasterImage::DecodeMetadata(uint32_t aFlags) {
return NS_OK;
}
void RasterImage::RecoverFromInvalidFrames(const UnorientedIntSize& aSize,
void RasterImage::RecoverFromInvalidFrames(const IntSize& aSize,
uint32_t aFlags) {
if (!mHasSize) {
return;
@ -1319,8 +1255,7 @@ void RasterImage::RecoverFromInvalidFrames(const UnorientedIntSize& aSize,
// Animated images require some special handling, because we normally require
// that they never be discarded.
if (mAnimationState) {
Decode(ToUnoriented(mSize), aFlags | FLAG_SYNC_DECODE,
PlaybackType::eAnimated);
Decode(mSize, aFlags | FLAG_SYNC_DECODE, PlaybackType::eAnimated);
ResetAnimation();
return;
}
@ -1337,7 +1272,7 @@ static bool HaveSkia() {
#endif
}
bool RasterImage::CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
bool RasterImage::CanDownscaleDuringDecode(const IntSize& aSize,
uint32_t aFlags) {
// Check basic requirements: downscale-during-decode is enabled, Skia is
// available, this image isn't transient, we have all the source data and know
@ -1354,8 +1289,7 @@ bool RasterImage::CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
}
// Never upscale.
UnorientedIntSize ourSize = ToUnoriented(mSize);
if (aSize.width >= ourSize.width || aSize.height >= ourSize.height) {
if (aSize.width >= mSize.width || aSize.height >= mSize.height) {
return false;
}
@ -1365,7 +1299,7 @@ bool RasterImage::CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
}
// There's no point in scaling if we can't store the result.
if (!SurfaceCache::CanHold(aSize.ToUnknownSize())) {
if (!SurfaceCache::CanHold(aSize)) {
return false;
}
@ -1374,7 +1308,7 @@ bool RasterImage::CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
ImgDrawResult RasterImage::DrawInternal(DrawableSurface&& aSurface,
gfxContext* aContext,
const UnorientedIntSize& aSize,
const IntSize& aSize,
const ImageRegion& aRegion,
SamplingFilter aSamplingFilter,
uint32_t aFlags, float aOpacity) {
@ -1390,7 +1324,7 @@ ImgDrawResult RasterImage::DrawInternal(DrawableSurface&& aSurface,
// adjust the drawing parameters accordingly.
IntSize finalSize = aSurface->GetSize();
bool couldRedecodeForBetterFrame = false;
if (finalSize != aSize.ToUnknownSize()) {
if (finalSize != aSize) {
gfx::Size scale(double(aSize.width) / finalSize.width,
double(aSize.height) / finalSize.height);
aContext->Multiply(gfxMatrix::Scaling(scale.width, scale.height));
@ -1448,8 +1382,7 @@ RasterImage::Draw(gfxContext* aContext, const IntSize& aSize,
? aFlags
: aFlags & ~FLAG_HIGH_QUALITY_SCALING;
auto size = ToUnoriented(OrientedIntSize::FromUnknownSize(aSize));
LookupResult result = LookupFrame(size, flags, ToPlaybackType(aWhichFrame),
LookupResult result = LookupFrame(aSize, flags, ToPlaybackType(aWhichFrame),
/* aMarkUsed = */ true);
if (!result) {
// Getting the frame (above) touches the image and kicks off decoding.
@ -1462,26 +1395,8 @@ RasterImage::Draw(gfxContext* aContext, const IntSize& aSize,
bool shouldRecordTelemetry =
!mDrawStartTime.IsNull() && result.Surface()->IsFinished();
ImgDrawResult drawResult;
{
gfxContextMatrixAutoSaveRestore asr;
ImageRegion region(aRegion);
if (!UsedOrientation().IsIdentity()) {
// Apply a transform so that the unoriented image is drawn in the
// orientation expected by the caller.
gfxMatrix matrix = OrientationMatrix(size);
asr.SetContext(aContext);
aContext->Multiply(matrix);
// Convert the region to unoriented coordinates.
gfxMatrix inverseMatrix = OrientationMatrix(size, /* aInvert = */ true);
region.TransformBoundsBy(inverseMatrix);
}
drawResult = DrawInternal(std::move(result.Surface()), aContext, size,
region, aSamplingFilter, flags, aOpacity);
}
auto drawResult = DrawInternal(std::move(result.Surface()), aContext, aSize,
aRegion, aSamplingFilter, flags, aOpacity);
if (shouldRecordTelemetry) {
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
@ -1586,8 +1501,7 @@ void RasterImage::DoError() {
SurfaceCache::RemoveImage(ImageKey(this));
// Invalidate to get rid of any partially-drawn image content.
auto dirtyRect = UnorientedIntRect({0, 0}, ToUnoriented(mSize));
NotifyProgress(NoProgress, dirtyRect);
NotifyProgress(NoProgress, IntRect(0, 0, mSize.width, mSize.height));
MOZ_LOG(gImgLog, LogLevel::Error,
("RasterImage: [this=%p] Error detected for image\n", this));
@ -1628,11 +1542,12 @@ RasterImage::GetFramesNotified(uint32_t* aFramesNotified) {
#endif
void RasterImage::NotifyProgress(
Progress aProgress,
const UnorientedIntRect& aInvalidRect /* = UnorientedIntRect() */,
Progress aProgress, const IntRect& aInvalidRect /* = IntRect() */,
const Maybe<uint32_t>& aFrameCount /* = Nothing() */,
DecoderFlags aDecoderFlags /* = DefaultDecoderFlags() */,
SurfaceFlags aSurfaceFlags /* = DefaultSurfaceFlags() */) {
DecoderFlags aDecoderFlags
/* = DefaultDecoderFlags() */,
SurfaceFlags aSurfaceFlags
/* = DefaultSurfaceFlags() */) {
MOZ_ASSERT(NS_IsMainThread());
// Ensure that we stay alive long enough to finish notifying.
@ -1640,11 +1555,9 @@ void RasterImage::NotifyProgress(
const bool wasDefaultFlags = aSurfaceFlags == DefaultSurfaceFlags();
auto invalidRect = ToOriented(aInvalidRect);
if (!invalidRect.IsEmpty() && wasDefaultFlags) {
if (!aInvalidRect.IsEmpty() && wasDefaultFlags) {
// Update our image container since we're invalidating.
UpdateImageContainer(Some(invalidRect.ToUnknownRect()));
UpdateImageContainer(Some(aInvalidRect));
}
if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY)) {
@ -1662,14 +1575,13 @@ void RasterImage::NotifyProgress(
}
// Tell the observers what happened.
image->mProgressTracker->SyncNotifyProgress(aProgress,
invalidRect.ToUnknownRect());
image->mProgressTracker->SyncNotifyProgress(aProgress, aInvalidRect);
}
void RasterImage::NotifyDecodeComplete(
const DecoderFinalStatus& aStatus, const ImageMetadata& aMetadata,
const DecoderTelemetry& aTelemetry, Progress aProgress,
const UnorientedIntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount,
const IntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount,
DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) {
MOZ_ASSERT(NS_IsMainThread());
@ -1684,8 +1596,7 @@ void RasterImage::NotifyDecodeComplete(
// This indicates a serious error that requires us to discard all existing
// surfaces and redecode to recover. We'll drop the results from this
// decoder on the floor, since they aren't valid.
RecoverFromInvalidFrames(ToUnoriented(mSize),
FromSurfaceFlags(aSurfaceFlags));
RecoverFromInvalidFrames(mSize, FromSurfaceFlags(aSurfaceFlags));
return;
}
@ -1707,14 +1618,10 @@ void RasterImage::NotifyDecodeComplete(
// AnimationState has been notified about them all, so let it know not to
// expect anymore.
mAnimationState->NotifyDecodeComplete();
auto size = ToUnoriented(mSize);
IntRect rect = mAnimationState->UpdateState(mAnimationFinished, this,
size.ToUnknownSize());
gfx::IntRect rect =
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
if (!rect.IsEmpty()) {
auto dirtyRect = UnorientedIntRect::FromUnknownRect(rect);
NotifyProgress(NoProgress, dirtyRect);
NotifyProgress(NoProgress, rect);
}
}
@ -1754,7 +1661,7 @@ void RasterImage::NotifyDecodeComplete(
// If we were a metadata decode and a full decode was requested, do it.
if (mWantFullDecode) {
mWantFullDecode = false;
RequestDecodeForSize(mSize.ToUnknownSize(),
RequestDecodeForSize(mSize,
DECODE_FLAGS_DEFAULT | FLAG_HIGH_QUALITY_SCALING,
FRAME_CURRENT);
}
@ -1806,90 +1713,15 @@ IntSize RasterImage::OptimalImageSizeForDest(const gfxSize& aDest,
return IntSize(0, 0);
}
auto dest = OrientedIntSize::FromUnknownSize(
IntSize::Ceil(aDest.width, aDest.height));
IntSize destSize = IntSize::Ceil(aDest.width, aDest.height);
if (aSamplingFilter == SamplingFilter::GOOD &&
CanDownscaleDuringDecode(ToUnoriented(dest), aFlags)) {
return dest.ToUnknownSize();
CanDownscaleDuringDecode(destSize, aFlags)) {
return destSize;
}
// We can't scale to this size. Use our intrinsic size for now.
return mSize.ToUnknownSize();
}
gfxMatrix RasterImage::OrientationMatrix(const UnorientedIntSize& aSize,
bool aInvert) const {
return OrientedImage::OrientationMatrix(UsedOrientation(),
aSize.ToUnknownSize(), aInvert);
}
/**
* Rotate aRect by the given angle within the space specified by aSize.
*
* For example, with aRect = [20, 10, 5, 5] and aSize = [100, 100], rotating
* with Angle::D90 will result in aRect = [85, 20, 5, 5].
*/
static void Rotate(IntRect& aRect, const IntSize& aSize, Angle aAngle) {
switch (aAngle) {
case Angle::D0:
break;
case Angle::D90:
aRect = {aSize.height - aRect.YMost(), aRect.x, aRect.height,
aRect.width};
break;
case Angle::D180:
aRect.MoveTo(aSize.width - aRect.XMost(), aSize.height - aRect.YMost());
break;
case Angle::D270:
aRect = {aRect.y, aSize.width - aRect.XMost(), aRect.height, aRect.width};
break;
}
}
/**
* Flip aRect along the central axis within aSize.
*
* For example, with aRect = [20, 10, 5, 5] and aSize = [100, 100], flipping
* with Flip::Horizontal will result in aRect = [75, 10, 5, 5].
*/
static void Flip(IntRect& aRect, const IntSize& aSize, Flip aFlip) {
switch (aFlip) {
case Flip::Unflipped:
break;
case Flip::Horizontal:
aRect.x = aSize.width - aRect.XMost();
break;
}
}
OrientedIntRect RasterImage::ToOriented(UnorientedIntRect aRect) const {
IntRect rect = aRect.ToUnknownRect();
auto size = ToUnoriented(mSize);
MOZ_ASSERT(!UsedOrientation().flipFirst,
"flipFirst should only be used by OrientedImage");
// UsedOrientation() specifies the transformation from a correctly oriented
// image to the pixels stored in the file, so we need to rotate by the
// negation of the given angle.
Angle angle = Orientation::InvertAngle(UsedOrientation().rotation);
Rotate(rect, size.ToUnknownSize(), angle);
Flip(rect, size.ToUnknownSize(), UsedOrientation().flip);
return OrientedIntRect::FromUnknownRect(rect);
}
UnorientedIntRect RasterImage::ToUnoriented(OrientedIntRect aRect) const {
IntRect rect = aRect.ToUnknownRect();
Flip(rect, mSize.ToUnknownSize(), UsedOrientation().flip);
Rotate(rect, mSize.ToUnknownSize(), UsedOrientation().rotation);
MOZ_ASSERT(!UsedOrientation().flipFirst,
"flipFirst should only be used by OrientedImage");
return UnorientedIntRect::FromUnknownRect(rect);
return mSize;
}
} // namespace image

View File

@ -32,7 +32,6 @@
#include "mozilla/Maybe.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/NotNull.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/UniquePtr.h"
@ -124,25 +123,6 @@ class nsIRequest;
namespace mozilla {
// Pixel values in an image considering orientation metadata, such as the size
// of an image as seen by consumers of the image.
//
// Any public methods on RasterImage that use untyped units are interpreted as
// oriented pixels.
struct OrientedPixel {};
template <>
struct IsPixel<OrientedPixel> : std::true_type {};
typedef gfx::IntSizeTyped<OrientedPixel> OrientedIntSize;
typedef gfx::IntRectTyped<OrientedPixel> OrientedIntRect;
// Pixel values in an image ignoring orientation metadata, such as are stored
// in surfaces and the raw pixel data in the image.
struct UnorientedPixel {};
template <>
struct IsPixel<UnorientedPixel> : std::true_type {};
typedef gfx::IntSizeTyped<UnorientedPixel> UnorientedIntSize;
typedef gfx::IntRectTyped<UnorientedPixel> UnorientedIntRect;
namespace layers {
class ImageContainer;
class Image;
@ -213,12 +193,11 @@ class RasterImage final : public ImageResource,
* these notifications, or DefaultSurfaceFlags() if the
* notifications don't come from a decoder.
*/
void NotifyProgress(
Progress aProgress,
const UnorientedIntRect& aInvalidRect = UnorientedIntRect(),
const Maybe<uint32_t>& aFrameCount = Nothing(),
DecoderFlags aDecoderFlags = DefaultDecoderFlags(),
SurfaceFlags aSurfaceFlags = DefaultSurfaceFlags());
void NotifyProgress(Progress aProgress,
const gfx::IntRect& aInvalidRect = nsIntRect(),
const Maybe<uint32_t>& aFrameCount = Nothing(),
DecoderFlags aDecoderFlags = DefaultDecoderFlags(),
SurfaceFlags aSurfaceFlags = DefaultSurfaceFlags());
/**
* Records decoding results, sends out any final notifications, updates the
@ -241,7 +220,7 @@ class RasterImage final : public ImageResource,
void NotifyDecodeComplete(
const DecoderFinalStatus& aStatus, const ImageMetadata& aMetadata,
const DecoderTelemetry& aTelemetry, Progress aProgress,
const UnorientedIntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount,
const gfx::IntRect& aInvalidRect, const Maybe<uint32_t>& aFrameCount,
DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags);
// Helper method for NotifyDecodeComplete.
@ -300,17 +279,15 @@ class RasterImage final : public ImageResource,
* @return a drawable surface, which may be empty if the requested surface
* could not be found.
*/
LookupResult LookupFrame(const UnorientedIntSize& aSize, uint32_t aFlags,
LookupResult LookupFrame(const gfx::IntSize& aSize, uint32_t aFlags,
PlaybackType aPlaybackType, bool aMarkUsed);
/// Helper method for LookupFrame().
LookupResult LookupFrameInternal(const UnorientedIntSize& aSize,
uint32_t aFlags, PlaybackType aPlaybackType,
bool aMarkUsed);
LookupResult LookupFrameInternal(const gfx::IntSize& aSize, uint32_t aFlags,
PlaybackType aPlaybackType, bool aMarkUsed);
ImgDrawResult DrawInternal(DrawableSurface&& aFrameRef, gfxContext* aContext,
const UnorientedIntSize& aSize,
const ImageRegion& aRegion,
const nsIntSize& aSize, const ImageRegion& aRegion,
gfx::SamplingFilter aSamplingFilter,
uint32_t aFlags, float aOpacity);
@ -339,7 +316,7 @@ class RasterImage final : public ImageResource,
*
* Returns true of the decode was run synchronously.
*/
bool Decode(const UnorientedIntSize& aSize, uint32_t aFlags,
bool Decode(const gfx::IntSize& aSize, uint32_t aFlags,
PlaybackType aPlaybackType);
/**
@ -375,66 +352,19 @@ class RasterImage final : public ImageResource,
* RecoverFromInvalidFrames discards all existing frames and redecodes using
* the provided @aSize and @aFlags.
*/
void RecoverFromInvalidFrames(const UnorientedIntSize& aSize,
uint32_t aFlags);
void RecoverFromInvalidFrames(const nsIntSize& aSize, uint32_t aFlags);
void OnSurfaceDiscardedInternal(bool aAnimatedFramesDiscarded);
/**
* Computes a matrix that applies the rotation and reflection specified by
* UsedOrientation(), or that matrix's inverse if aInvert is true.
*
* See OrientedImage::OrientationMatrix.
*/
gfxMatrix OrientationMatrix(const UnorientedIntSize& aSize,
bool aInvert = false) const;
/**
* The orientation value to honor for this image.
*
* If the image.honor-orientation-metadata pref is true, then this returns
* the orientation from the image's metadata. Otherwise, it returns an
* Orientation that indicates no transformation is needed.
*/
Orientation UsedOrientation() const {
return mHandledOrientation ? mOrientation : Orientation();
}
// Functions to convert between oriented and unoriented pixels.
UnorientedIntSize ToUnoriented(OrientedIntSize aSize) const {
return UsedOrientation().SwapsWidthAndHeight()
? UnorientedIntSize(aSize.height, aSize.width)
: UnorientedIntSize(aSize.width, aSize.height);
}
OrientedIntSize ToOriented(UnorientedIntSize aSize) const {
return UsedOrientation().SwapsWidthAndHeight()
? OrientedIntSize(aSize.height, aSize.width)
: OrientedIntSize(aSize.width, aSize.height);
}
OrientedIntRect ToOriented(UnorientedIntRect aRect) const;
UnorientedIntRect ToUnoriented(OrientedIntRect aRect) const;
private: // data
OrientedIntSize mSize;
nsTArray<OrientedIntSize> mNativeSizes;
// The orientation required to correctly orient the image, from the image's
// metadata.
//
// When the image.honor-orientation-metadata pref is enabled, the RasterImage
// will handle and apply this orientation itself.
//
// When the pref is disabled, it is the responsibility of users of the
// RasterImage to wrap it in an OrientedImage if desired.
nsIntSize mSize;
nsTArray<nsIntSize> mNativeSizes;
Orientation mOrientation;
/// If this has a value, we're waiting for SetSize() to send the load event.
Maybe<Progress> mLoadProgress;
// Hotspot of this image, or (0, 0) if there is no hotspot data.
//
// We assume (and assert) that no image has both orientation metadata and a
// hotspot, so we store this as an untyped point.
gfx::IntPoint mHotspot;
/// If this image is animated, a FrameAnimator which manages its animation.
@ -483,15 +413,6 @@ class RasterImage final : public ImageResource,
// kick off a full decode.
bool mWantFullDecode : 1;
// Whether this RasterImage handled orientation of the image.
//
// This will be set based on the value of the image.honor-orientation-metadata
// pref at the time the RasterImage is created.
//
// NOTE(heycam): Once the image.honor-orientation-metadata pref is removed,
// this member (and the UsedOrientation() function) can also be removed.
bool mHandledOrientation : 1;
TimeStamp mDrawStartTime;
//////////////////////////////////////////////////////////////////////////////
@ -500,8 +421,7 @@ class RasterImage final : public ImageResource,
// Determines whether we can downscale during decode with the given
// parameters.
bool CanDownscaleDuringDecode(const UnorientedIntSize& aSize,
uint32_t aFlags);
bool CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags);
// Error handling.
void DoError();
@ -528,7 +448,7 @@ class RasterImage final : public ImageResource,
bool IsOpaque();
DrawableSurface RequestDecodeForSizeInternal(const UnorientedIntSize& aSize,
DrawableSurface RequestDecodeForSizeInternal(const gfx::IntSize& aSize,
uint32_t aFlags,
uint32_t aWhichFrame);

View File

@ -562,10 +562,6 @@ class ImageSurfaceCache {
MOZ_ASSERT_UNREACHABLE("Expected valid native size!");
return aSize;
}
if (image->GetOrientation().SwapsWidthAndHeight() &&
image->HandledOrientation()) {
std::swap(factorSize.width, factorSize.height);
}
if (mIsVectorImage) {
// Ensure the aspect ratio matches the native size before forcing the

View File

@ -651,9 +651,6 @@ Maybe<AspectRatio> VectorImage::GetIntrinsicRatio() {
NS_IMETHODIMP_(Orientation)
VectorImage::GetOrientation() { return Orientation(); }
NS_IMETHODIMP_(bool)
VectorImage::HandledOrientation() { return false; }
//******************************************************************************
NS_IMETHODIMP
VectorImage::GetType(uint16_t* aType) {

View File

@ -623,12 +623,6 @@ interface imgIContainer : nsISupports
*/
[notxpcom] Orientation getOrientation();
/*
* Returns whether the image handles the orientation returned by
* getOrientation() itself.
*/
[notxpcom] bool handledOrientation();
/*
* Returns the delay, in ms, between the first and second frame. If this
* returns 0, there is no delay between first and second frame (i.e., this

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html class="reftest-wait">
<head>
<script>
function snapshot() {
document.documentElement.removeAttribute('class');
}
</script>
</head>
<!-- NOTE: Using setTimeout to wait for high-quality downscaled version of
image to be ready, because there's nothing better we can do. If we fix
Bug 1006883, we can do away with this setTimeout.
For now, the setTimeout is just here to increase the likelihood that we
actually test the high-quality downscaled version of the image. If the
setTimeout happens to fire before the high-quality downscaled rendering is
ready, then this the test will pass without testing what it's trying to
test, which is fine as long as that's rare. -->
<body onload="setTimeout(snapshot, 50)">
<img src="image-pre-rotated-90-deg.jpg" style="width: 50px; height: 25px;">
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<html class="reftest-wait">
<head>
<script>
function snapshot() {
document.documentElement.removeAttribute('class');
}
</script>
</head>
<!-- NOTE: Using setTimeout to wait for high-quality downscaled version of
image to be ready, because there's nothing better we can do. If we fix
Bug 1006883, we can do away with this setTimeout.
For now, the setTimeout is just here to increase the likelihood that we
actually test the high-quality downscaled version of the image. If the
setTimeout happens to fire before the high-quality downscaled rendering is
ready, then this the test will pass without testing what it's trying to
test, which is fine as long as that's rare. -->
<body onload="setTimeout(snapshot, 50)">
<img src="../../../../layout/reftests/image/image-exif-90-deg.jpg" style="width: 50px; height: 25px;">
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -110,9 +110,6 @@ fuzzy(0-1,0-1024) == downscale-32px.html?.jpg downscale-32px-ref.html
== downscale-32px.html?-bmp-in.ico downscale-32px-ref.html
== downscale-32px.html?-png-in.ico downscale-32px-ref.html
# Test downscaling a JPEG with orientation metadata.
fuzzy(0-1,0-50) == downscale-orient.html downscale-orient-ref.html
# RUN TESTS WITH DOWNSCALE-DURING-DECODE ENABLED:
# ===============================================
defaults pref(image.downscale-during-decode.enabled,true)
@ -199,9 +196,6 @@ fuzzy(0-18,0-128) == downscale-32px.html?.png downscale-32px-ref.html
fuzzy(0-18,0-128) == downscale-32px.html?-bmp-in.ico downscale-32px-ref.html
fuzzy(0-18,0-128) == downscale-32px.html?-png-in.ico downscale-32px-ref.html
# Test downscaling a JPEG with orientation metadata.
fuzzy(0-4,0-15) == downscale-orient.html downscale-orient-ref.html
# Test images taller or wider than 32767 pixels.
== huge-1.html?100x32768.png,100,100 huge-1.html?100x100.png,100,100
== huge-1.html?100x32768.png,100,32768 huge-1.html?100x100.png,100,32768

View File

@ -29,7 +29,6 @@
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_font.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/StaticPrefs_layers.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/Unused.h"
@ -7202,19 +7201,8 @@ already_AddRefed<imgIContainer> nsLayoutUtils::OrientImage(
MOZ_ASSERT(aContainer, "Should have an image container");
nsCOMPtr<imgIContainer> img(aContainer);
bool handledOrientation = img->HandledOrientation();
switch (aOrientation) {
case StyleImageOrientation::FromImage:
if (!handledOrientation) {
img = ImageOps::Orient(img, img->GetOrientation());
}
break;
case StyleImageOrientation::None:
if (handledOrientation) {
img = ImageOps::Unorient(img);
}
break;
if (aOrientation == StyleImageOrientation::FromImage) {
img = ImageOps::Orient(img, img->GetOrientation());
}
return img.forget();
@ -7603,17 +7591,6 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
return result;
}
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
// Ensure that the image is oriented the same way as it's displayed.
auto orientation = StaticPrefs::image_honor_orientation_metadata()
? StyleImageOrientation::FromImage
: StyleImageOrientation::None;
if (nsIFrame* f = content->GetPrimaryFrame()) {
orientation = f->StyleVisibility()->mImageOrientation;
}
imgContainer = OrientImage(imgContainer, orientation);
uint32_t noRasterize = aSurfaceFlags & SFE_NO_RASTERIZING_VECTORS;
uint32_t whichFrame = (aSurfaceFlags & SFE_WANT_FIRST_FRAME_IF_IMAGE)
@ -7628,6 +7605,7 @@ nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
}
int32_t imgWidth, imgHeight;
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
HTMLImageElement* element = HTMLImageElement::FromNodeOrNull(content);
if (aSurfaceFlags & SFE_USE_ELEMENT_SIZE_IF_VECTOR && element &&
imgContainer->GetType() == imgIContainer::TYPE_VECTOR) {

View File

@ -1,3 +0,0 @@
<!DOCTYPE html>
<div style="width: 200px; height: 100px;"><img src="../image/image-exif-90-deg.jpg"></div>
<img src="../image/image-exif-90-deg.jpg">

View File

@ -1,4 +0,0 @@
<!DOCTYPE html>
<!-- Test that -moz-element() honors a target image's orientation metadata. -->
<div style="width: 200px; height: 100px; background-image: -moz-element(#e);"></div>
<img id="e" src="../image/image-exif-90-deg.jpg">

View File

@ -49,5 +49,5 @@ HTTP == invalidate-1.html invalidate-1-ref.html
== empty-src.html no-src.html
== broken-icon.html invalid-src.html
fails == invalid-src.html invalid-src-2.html # bug 1506804
fuzzy-if(skiaContent,0-1,0-30000) == mask-image-element.html mask-image-element-ref.html
pref(image.honor-orientation-metadata,true) pref(layout.css.image-orientation.initial-from-image,true) == orientation-1.html orientation-1-ref.html

View File

@ -0,0 +1,41 @@
<!DOCTYPE>
<head>
<style>
body {
border: 0px;
margin: 0px;
padding: 0px;
}
div {
width: 100px;
height: 100px;
margin: 50px;
/* This is deliberately an image with a non-neutral inherent orientation to */
/* ensure that the inherent orientation is irrelevant. */
border-style: solid;
border-width: 20px;
border-image: url(image-exif-90-deg-flip.jpg) 27 repeat;
}
</style>
</head>
<body>
<div></div>
<script>
var fromImage = location.search == "from-image";
// Construct a style.
var style;
if (fromImage) {
style = "div { image-orientation: from-image; }\n";
} else {
style = "div { image-orientation: none; }\n";
}
// Apply the style to the document.
var sheet = document.createElement('style');
sheet.innerHTML = style;
document.body.appendChild(sheet);
</script>
</body>

View File

@ -0,0 +1,39 @@
<!DOCTYPE>
<head>
<style>
body {
border: 0px;
margin: 0px;
padding: 0px;
}
ul {
list-style-position: inside;
list-style-image: url(image-exif-270-deg-flip.jpg);
}
</style>
</head>
<body>
<ul><li></li></ul>
<script>
var orientation = location.search.substring(1).split("&");
var angle = orientation[0];
var flip = orientation[1] == "flip" ? true : false;
// Construct a style. "from-image" is special-cased.
var style;
if (angle == "from-image") {
style = "ul { image-orientation: from-image; }\n";
} else {
style = "ul { image-orientation: "
+ angle + "deg"
+ (flip ? " flip" : "")
+ "; }\n";
}
// Apply the style to the document.
var sheet = document.createElement('style');
sheet.innerHTML = style;
document.body.appendChild(sheet);
</script>
</body>

View File

@ -38,6 +38,11 @@ fuzzy(0-1,0-1) == image-orientation-explicit-none.html image-orientation-ref.htm
# Tests for image-orientation:from-image used on generated content:
fuzzy(0-1,0-1) == image-orientation-generated-content.html image-orientation-generated-content-ref.html
# Tests that image-orientation does not apply to decorative images:
fuzzy(0-1,0-1) == image-orientation-background.html?from-image image-orientation-ref.html?none
== image-orientation-border-image.html?from-image image-orientation-border-image.html?none
== image-orientation-list-style-image.html?from-image image-orientation-list-style-image.html?none
fuzzy(0-1,0-1) == image-orientation-dynamic.html image-orientation-dynamic-ref.html
# <img srcset> tests

View File

@ -4362,15 +4362,6 @@
value: true
mirror: always
# Whether to honor orientation metadata (such as JPEG EXIF tags) by default.
# When this pref is enabled, all images used by the platform will be correctly
# re-oriented, except for content images (HTML <img> and CSS generated content
# images) with image-orientation:none.
- name: image.honor-orientation-metadata
type: RelaxedAtomicBool
value: true
mirror: always
# Honor image orientation metadata in the naturalWidth and naturalHeight
# APIs on HTMLImageElement.
- name: image.honor_orientation_metadata.natural_size
@ -5529,7 +5520,7 @@
# Is the initial value for the image-orientation property 'from-image'?
- name: layout.css.image-orientation.initial-from-image
type: RelaxedAtomicBool
value: true
value: @IS_NIGHTLY_BUILD@
mirror: always
rust: true

View File

@ -1 +0,0 @@
prefs: [layout.css.image-orientation.initial-from-image:true, image.honor-orientation-metadata:true]

View File

@ -1,2 +0,0 @@
[drawImage-from-bitmap-orientation-none.tentative.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[drawImage-from-bitmap-swap-width-height-orientation-none.tentative.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[drawImage-from-bitmap-swap-width-height.tentative.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[drawImage-from-bitmap.tentative.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[drawImage-from-element-orientation-none.tentative.html]
expected: FAIL

View File

@ -1,2 +0,0 @@
[drawImage-from-element-swap-width-height-orientation-none.tentative.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[drawImage-from-element-swap-width-height.tentative.html]
expected: FAIL

View File

@ -0,0 +1,2 @@
[drawImage-from-element.tentative.html]
expected: FAIL

View File

@ -1,2 +1 @@
leak-threshold: [default:51200]
prefs: [image.honor-orientation-metadata:true, layout.css.image-orientation.initial-from-image:true]

View File

@ -1,2 +0,0 @@
[image-orientation-background-image.html]
fuzzy: 2;40

View File

@ -1,2 +0,0 @@
[image-orientation-border-image.html]
fuzzy: 0-16;80-160

View File

@ -1,2 +0,0 @@
[image-orientation-list-style-image.html]
fuzzy: 2;40

View File

@ -1,2 +0,0 @@
[image-orientation-mask-image.html]
fuzzy: 1;22

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Images Module Level 3: image-orientation does not apply to background-image</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation">
<link rel="match" href="reference/image-orientation-background-image-ref.html">
<meta name=fuzzy content="2;40">
<style>
div { width: 100px; height: 50px; background-image: url(support/exif-orientation-2-ur.jpg); }
.no-orient { image-orientation: none; }
</style>
<div></div>
<div class="no-orient"></div>

View File

@ -1,17 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Images Module Level 3: image-orientation does not apply to border images</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation">
<link rel="match" href="reference/image-orientation-border-image-ref.html">
<style>
div {
width: 100px;
height: 50px;
border: 10px solid black;
border-image: url(support/exif-orientation-2-ur.jpg) 10;
}
.no-orient { image-orientation: none; }
</style>
<div></div>
<div class="no-orient"></div>

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Images Module Level 3: image-orientation does not apply to list-style-image</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation">
<link rel="match" href="reference/image-orientation-list-style-image-ref.html">
<meta name=fuzzy content="2;40">
<style>
ul { margin-left: 100px; list-style-image: url(support/exif-orientation-2-ur.jpg); }
.no-orient { image-orientation: none; }
</style>
<ul><li>&nbsp;</li></ul>
<ul class="no-orient"><li>&nbsp;</li></ul>

View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Images Module Level 3: image-orientation does not apply to mask-image</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-images-3/#propdef-image-orientation">
<link rel="match" href="reference/image-orientation-mask-image-ref.html">
<meta name=fuzzy content="1;22">
<style>
div {
width: 100px;
height: 50px;
background: blue;
mask-image: url(support/exif-orientation-2-ur.jpg);
mask-mode: luminance;
}
.no-orient { image-orientation: none; }
</style>
<div></div>
<div class="no-orient"></div>

View File

@ -1,9 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
div { width: 100px; height: 50px; background-image: url(../support/exif-orientation-2-ur-pre-rotated.jpg); }
</style>
<div></div>
<div></div>

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
div {
width: 100px;
height: 50px;
border: 10px solid black;
border-image: url(../support/exif-orientation-2-ur-pre-rotated.jpg) 10;
}
</style>
<div></div>
<div></div>

View File

@ -1,8 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
ul { margin-left: 100px; list-style-image: url(../support/exif-orientation-2-ur-pre-rotated.jpg); }
</style>
<ul><li>&nbsp;</li></ul>
<ul><li>&nbsp;</li></ul>

View File

@ -1,14 +0,0 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
div {
width: 100px;
height: 50px;
background: blue;
mask-image: url(../support/exif-orientation-2-ur-pre-rotated.jpg);
mask-mode: luminance;
}
</style>
<div></div>
<div></div>