mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Bug 1695404 - Support the type() function in image-set. r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D109201
This commit is contained in:
parent
713db94540
commit
6a6e08264c
@ -8,12 +8,15 @@
|
||||
|
||||
#include "mozilla/GeckoBindings.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ChildIterator.h"
|
||||
#include "ErrorReporter.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "gfxFontFamilyList.h"
|
||||
#include "gfxFontFeatures.h"
|
||||
#include "gfxTextRun.h"
|
||||
#include "imgLoader.h"
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsAttrValueInlines.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
@ -1269,6 +1272,13 @@ void Gecko_GetComputedImageURLSpec(const StyleComputedUrl* aURL,
|
||||
aOut->AssignLiteral("about:invalid");
|
||||
}
|
||||
|
||||
bool Gecko_IsSupportedImageMimeType(const uint8_t* mime_type,
|
||||
const uint32_t len) {
|
||||
std::string aMimeType(reinterpret_cast<const char*>(mime_type), len);
|
||||
return imgLoader::SupportImageWithMimeType(
|
||||
aMimeType.c_str(), AcceptedMimeTypes::IMAGES_AND_DOCUMENTS);
|
||||
}
|
||||
|
||||
void Gecko_nsIURI_Debug(nsIURI* aURI, nsCString* aOut) {
|
||||
// TODO(emilio): Do we have more useful stuff to put here, maybe?
|
||||
if (aURI) {
|
||||
|
@ -461,6 +461,10 @@ void Gecko_GetComputedURLSpec(const mozilla::StyleComputedUrl* url,
|
||||
void Gecko_GetComputedImageURLSpec(const mozilla::StyleComputedUrl* url,
|
||||
nsCString* spec);
|
||||
|
||||
// Return true if the given image MIME type is supported
|
||||
bool Gecko_IsSupportedImageMimeType(const uint8_t* mime_type,
|
||||
const uint32_t len);
|
||||
|
||||
void Gecko_nsIURI_Debug(nsIURI*, nsCString* spec);
|
||||
|
||||
void Gecko_nsIReferrerInfo_Debug(nsIReferrerInfo* aReferrerInfo,
|
||||
|
@ -278,6 +278,9 @@ var validNonUrlImageValues = [
|
||||
"image-set(url(foobar.png) 1x, url(bar.png) 2x, url(baz.png) 3x)",
|
||||
"image-set('foobar.png', 'bar.png' 2x, url(baz.png) 3x)",
|
||||
"image-set(image-set('foobar.png', 'bar.png' 2x) 1x, url(baz.png) 3x)",
|
||||
"image-set(url(foobar.png) type('image/png'))",
|
||||
"image-set(url(foobar.png) 1x type('image/png'))",
|
||||
"image-set(url(foobar.png) type('image/png') 1x)",
|
||||
]
|
||||
: []),
|
||||
|
||||
@ -824,6 +827,11 @@ var invalidNonUrlImageValues = [
|
||||
"image-set(garbage)",
|
||||
"image-set(image-set(garbage))",
|
||||
"image-set()",
|
||||
"image-set(type('image/png') url(foobar.png) 1x)",
|
||||
"image-set(url(foobar.png) type('image/png') 1x type('image/png'))",
|
||||
"image-set(url(foobar.png) type('image/png') type('image/png'))",
|
||||
"image-set(url(foobar.png) type(image/png))",
|
||||
"image-set(url(foobar.png) epyt('image/png'))",
|
||||
]
|
||||
: []),
|
||||
|
||||
|
@ -360,4 +360,11 @@ impl Device {
|
||||
};
|
||||
SideOffsets2D::new(top, right, bottom, left)
|
||||
}
|
||||
|
||||
/// Returns true if the given MIME type is supported
|
||||
pub fn is_supported_mime_type(&self, mime_type: &str) -> bool {
|
||||
unsafe {
|
||||
bindings::Gecko_IsSupportedImageMimeType(mime_type.as_ptr(), mime_type.len() as u32)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,9 +74,20 @@ impl ToComputedValue for specified::ImageSet {
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
let items = self.items.to_computed_value(context);
|
||||
let dpr = context.device().device_pixel_ratio().get();
|
||||
|
||||
// If no item have a supported MIME type, the behavior is undefined by the standard
|
||||
// By default, we select the first item
|
||||
let mut supported_image = false;
|
||||
let mut selected_index = 0;
|
||||
let mut selected_resolution = items[0].resolution.dppx();
|
||||
for (i, item) in items.iter().enumerate().skip(1) {
|
||||
|
||||
for (i, item) in items.iter().enumerate() {
|
||||
|
||||
// If the MIME type is not supported, we discard the ImageSetItem
|
||||
if item.has_mime_type && !context.device().is_supported_mime_type(&item.mime_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let candidate_resolution = item.resolution.dppx();
|
||||
|
||||
// https://drafts.csswg.org/css-images-4/#image-set-notation:
|
||||
@ -97,7 +108,9 @@ impl ToComputedValue for specified::ImageSet {
|
||||
false
|
||||
};
|
||||
|
||||
if better_candidate() {
|
||||
// The first item with a supported MIME type is obviously the current best candidate
|
||||
if !supported_image || better_candidate() {
|
||||
supported_image = true;
|
||||
selected_index = i;
|
||||
selected_resolution = candidate_resolution;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ pub struct GenericImageSet<Image, Resolution> {
|
||||
|
||||
/// An optional percent and a cross fade image.
|
||||
#[derive(
|
||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem, ToCss,
|
||||
Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
|
||||
)]
|
||||
#[repr(C)]
|
||||
pub struct GenericImageSetItem<Image, Resolution> {
|
||||
@ -142,7 +142,33 @@ pub struct GenericImageSetItem<Image, Resolution> {
|
||||
///
|
||||
/// TODO: Skip serialization if it is 1x.
|
||||
pub resolution: Resolution,
|
||||
// TODO: type() function.
|
||||
|
||||
/// The `type(<string>)`
|
||||
/// (Optional) Specify the image's MIME type
|
||||
pub mime_type: crate::OwnedStr,
|
||||
|
||||
/// True if mime_type has been specified
|
||||
pub has_mime_type: bool,
|
||||
}
|
||||
|
||||
impl<I: style_traits::ToCss, R: style_traits::ToCss> ToCss for GenericImageSetItem<I, R>
|
||||
{
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: fmt::Write,
|
||||
{
|
||||
self.image.to_css(dest)?;
|
||||
dest.write_str(" ")?;
|
||||
self.resolution.to_css(dest)?;
|
||||
|
||||
if self.has_mime_type {
|
||||
dest.write_str(" ")?;
|
||||
dest.write_str("type(")?;
|
||||
self.mime_type.to_css(dest)?;
|
||||
dest.write_str(")")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::GenericImageSet as ImageSet;
|
||||
|
@ -377,6 +377,13 @@ impl ImageSet {
|
||||
}
|
||||
|
||||
impl ImageSetItem {
|
||||
fn parse_type<'i>(p: &mut Parser<'i, '_>) -> Result<crate::OwnedStr, ParseError<'i>> {
|
||||
p.expect_function_matching("type")?;
|
||||
p.parse_nested_block(|input| {
|
||||
Ok(input.expect_string()?.as_ref().to_owned().into())
|
||||
})
|
||||
}
|
||||
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
@ -393,10 +400,20 @@ impl ImageSetItem {
|
||||
context, input, cors_mode, /* allow_none = */ false, /* only_url = */ only_url
|
||||
)?,
|
||||
};
|
||||
let resolution = input
|
||||
.try_parse(|input| Resolution::parse(context, input))
|
||||
.unwrap_or(Resolution::X(1.0));
|
||||
Ok(Self { image, resolution })
|
||||
|
||||
let mut resolution = input.try_parse(|input| Resolution::parse(context, input)).ok();
|
||||
let mime_type = input.try_parse(Self::parse_type).ok();
|
||||
|
||||
// Try to parse resolution after type().
|
||||
if mime_type.is_some() && resolution.is_none() {
|
||||
resolution = input.try_parse(|input| Resolution::parse(context, input)).ok();
|
||||
}
|
||||
|
||||
let resolution = resolution.unwrap_or(Resolution::X(1.0));
|
||||
let has_mime_type = mime_type.is_some();
|
||||
let mime_type = mime_type.unwrap_or_default();
|
||||
|
||||
Ok(Self { image, resolution, has_mime_type, mime_type })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
{ property: 'background-image', imageSet: "url(example.png) 1dpcm, 'example.png' 2x", valid: true },
|
||||
{ property: 'background-image', imageSet: "'example.jpeg' 222dpi, url(example.png) 3.5x", valid: true },
|
||||
{ property: 'background-image', imageSet: "linear-gradient(black, white) 1x", valid: true },
|
||||
{ property: 'background-image', imageSet: "url(example.png) 1x type('image/png')", valid: true },
|
||||
{ property: 'background-image', imageSet: "url(example.png) type('image/png')", valid: true },
|
||||
{ property: 'background-image', imageSet: "url(example.png) type('image/png') 1x", valid: true },
|
||||
{ property: 'content', imageSet: "linear-gradient(black, white) 1x, 'example.png' 4x", valid: true },
|
||||
{ property: 'content', imageSet: "url('example.png') 192dpi, linear-gradient(black, white) 1x", valid: true },
|
||||
|
||||
@ -28,6 +31,10 @@
|
||||
{ property: 'background-image', imageSet: "url(example.png) 0x", valid: false },
|
||||
{ property: 'background-image', imageSet: "url(example.png) -20x", valid: false },
|
||||
{ property: 'background-image', imageSet: "'example.jpeg' 92pid url(example.png) 1x", valid: false },
|
||||
{ property: 'background-image', imageSet: "url(example.png) type(image/png)", valid: false },
|
||||
{ property: 'background-image', imageSet: "url(example.png) type('image/png') type('image/png')", valid: false },
|
||||
{ property: 'background-image', imageSet: "url(example.png) 1xtype('image/png')", valid: false },
|
||||
{ property: 'background-image', imageSet: "type('image/png') url(example.png) 1x", valid: false },
|
||||
{ property: 'cursor', imageSet: "linear-gradient(black, white) 1x", valid: false }
|
||||
]
|
||||
|
||||
|
@ -32,6 +32,13 @@
|
||||
<div class="test" style="background-color: lime"></div>
|
||||
<div class="test" style="background-color: lime"></div>
|
||||
<div class="test" style="background-color: lime"></div>
|
||||
<div class="test" style="background-image: url(/images/green.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/green.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/green.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/red.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/green.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/red.png)"></div>
|
||||
<div class="test" style="background-image: url(/images/green.png)"></div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -34,6 +34,13 @@
|
||||
<div class="test" style="background-color: red; background-image: image-set('/images/green.png')" ></div>
|
||||
<div class="test" style="background-color: lime; background-image: image-set('/images/red.png' 0x)" ></div>
|
||||
<div class="test" style="background-color: lime; background-image: image-set('/images/red.png' 0x, url('/images/red.png') 2x)" ></div>
|
||||
<div class="test" style="background-image: image-set('/images/green.png' type('image/png') 1x)"></div>
|
||||
<div class="test" style="background-image: image-set('/images/green.png' 1x type('image/png'))"></div>
|
||||
<div class="test" style="background-image: image-set('/images/green.png' type('image/png'))"></div>
|
||||
<div class="test" style="background-image: image-set('/images/red.png' type('image/png'), '/images/green.png' type('image/png'))"></div>
|
||||
<div class="test" style="background-image: image-set('/images/red.png' type('image/unsupported'), '/images/green.png' type('image/png'))"></div>
|
||||
<div class="test" style="background-image: image-set('/images/red.png' type('image/unsupported'), '/images/green.png' type('image/unsupported'))"></div>
|
||||
<div class="test" style="background-image: image-set('/images/red.png' 2x type('image/png'), '/images/green.png' 1x type('image/png'))"></div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user