Skip to content

Commit b98ebc9

Browse files
Resolve functional blur lengths (#490)
1 parent 0043fd5 commit b98ebc9

3 files changed

Lines changed: 59 additions & 10 deletions

File tree

‎experiments/WebScene.NativeEngine.Probe/native/webscene_native_dom_scene.inc‎

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,18 @@ void native_document::append_scene(
379379
return result;
380380
}
381381
const auto opening = remaining.find('(');
382-
const auto closing = opening == std::string_view::npos
383-
? std::string_view::npos : remaining.find(')', opening + 1U);
382+
auto closing = std::string_view::npos;
383+
if (opening != std::string_view::npos) {
384+
auto depth = 1U;
385+
for (auto index = opening + 1U; index < remaining.size(); ++index) {
386+
if (remaining[index] == '(') {
387+
++depth;
388+
} else if (remaining[index] == ')' && --depth == 0U) {
389+
closing = index;
390+
break;
391+
}
392+
}
393+
}
384394
if (opening == 0U || opening == std::string_view::npos
385395
|| closing == std::string_view::npos) {
386396
result.clear();
@@ -389,21 +399,39 @@ void native_document::append_scene(
389399
const auto name = trim(remaining.substr(0U, opening));
390400
const auto argument = trim(
391401
remaining.substr(opening + 1U, closing - opening - 1U));
392-
const auto parsed = css::parse_ascii_number_prefix(argument);
393-
if (!parsed.has_value() || parsed->value < 0.0F) {
394-
result.clear();
395-
return result;
396-
}
397-
const auto suffix = argument.substr(parsed->consumed);
398402
uint32_t flags = 0U;
399403
float amount = -1.0F;
400404
float maximum = 0.0F;
401405
if (equals_ascii_case_insensitive(name, "blur")) {
402406
flags = 1U << 28U;
403407
maximum = 256.0F;
404-
amount = suffix == "px" || (suffix.empty() && parsed->value == 0.0F)
405-
? parsed->value : -1.0F;
408+
const auto length = parse_length(std::string{argument});
409+
switch (length.unit) {
410+
case length_unit::pixels:
411+
case length_unit::em:
412+
case length_unit::rem:
413+
case length_unit::viewport_width:
414+
case length_unit::viewport_height:
415+
case length_unit::viewport_width_capped:
416+
case length_unit::viewport_height_capped:
417+
case length_unit::viewport_width_floored:
418+
case length_unit::viewport_height_floored:
419+
case length_unit::container_inline:
420+
case length_unit::container_block:
421+
case length_unit::container_min:
422+
case length_unit::container_max:
423+
amount = resolve_length(node, length, 0.0F, -1.0F);
424+
break;
425+
default:
426+
break;
427+
}
406428
} else {
429+
const auto parsed = css::parse_ascii_number_prefix(argument);
430+
if (!parsed.has_value() || parsed->value < 0.0F) {
431+
result.clear();
432+
return result;
433+
}
434+
const auto suffix = argument.substr(parsed->consumed);
407435
if (equals_ascii_case_insensitive(name, "brightness")) {
408436
flags = 1U << 31U;
409437
maximum = 10.0F;

‎experiments/WebScene.NativeEngine.Probe/tests/native_css_effect_values_tests.cpp‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct clip_scene_counts final {
5555
uint32_t inset_clip_ends{};
5656
uint32_t clipped_fills{};
5757
uint32_t blur_filter_begins{};
58+
uint32_t functional_blur_begins{};
5859
uint32_t command_count{};
5960
bool transform_clip_nested{};
6061
bool compound_filter_ordered{};
@@ -137,6 +138,10 @@ clip_scene_counts wait_for_inset_clip_scene(webscene_engine* engine, uint32_t ex
137138
&& (command.flags & (1U << 28U)) != 0U
138139
&& std::abs(command.stroke_width - 2.0F) < 0.01F) {
139140
++latest.blur_filter_begins;
141+
} else if (command.kind == 30U
142+
&& (command.flags & (1U << 28U)) != 0U
143+
&& std::abs(command.stroke_width - 4.0F) < 0.01F) {
144+
++latest.functional_blur_begins;
140145
}
141146
}
142147
webscene_scene_acknowledge_v3(lease);
@@ -209,6 +214,7 @@ int main()
209214
clip-path: inset(0px 1px); filter: brightness(0.5); backdrop-filter: blur(1px); }
210215
#effects.alternate > span { clip-path: circle(25%); filter: contrast(2); }
211216
#effects > span:first-child { transform: scale(1.25) rotate(3deg); }
217+
#functional-blur { filter: blur(max(4px, calc(8px * 0.25))); }
212218
#compound-filter { filter: blur(2px) saturate(1.08) contrast(1.5) grayscale(0.25); }
213219
#effects > span:last-child { filter: blur(2px); }
214220
`;
@@ -218,6 +224,7 @@ int main()
218224
const fragment = document.createDocumentFragment();
219225
for (let index = 0; index < 4096; index++) fragment.appendChild(document.createElement('span'));
220226
host.appendChild(fragment);
227+
host.children[4093].id = 'functional-blur';
221228
host.children[4094].id = 'compound-filter';
222229
document.body.appendChild(host);
223230
const first = host.firstElementChild;
@@ -235,6 +242,10 @@ int main()
235242
!== 'blur(2px) saturate(1.08) contrast(1.5) grayscale(0.25)') {
236243
throw new Error('initial compound filter list failed');
237244
}
245+
if (getComputedStyle(document.getElementById('functional-blur')).getPropertyValue('filter')
246+
!== 'blur(max(4px, calc(8px * 0.25)))') {
247+
throw new Error('initial functional blur value failed');
248+
}
238249
})()
239250
)JS", "native-effects-fixture.js");
240251

@@ -305,6 +316,8 @@ int main()
305316
"retained scene did not emit both bounded foreground blur groups");
306317
require(initial_clip_scene.compound_filter_ordered,
307318
"retained scene did not preserve compound foreground filter order");
319+
require(initial_clip_scene.functional_blur_begins == 1U,
320+
"retained scene did not resolve the functional blur radius");
308321
const auto initial_scene_command_bytes =
309322
static_cast<uint64_t>(initial_clip_scene.command_count)
310323
* sizeof(webscene_scene_command);
@@ -417,6 +430,7 @@ int main()
417430
<< " clip-ends=" << initial_clip_scene.inset_clip_ends
418431
<< " clipped-fills=" << initial_clip_scene.clipped_fills
419432
<< " blur-filter-begins=" << initial_clip_scene.blur_filter_begins
433+
<< " functional-blur-begins=" << initial_clip_scene.functional_blur_begins
420434
<< " compound-filter-ordered=" << initial_clip_scene.compound_filter_ordered
421435
<< " transform-clip-nested=" << initial_clip_scene.transform_clip_nested
422436
<< " initial-scene-command-bytes=" << initial_scene_command_bytes

‎tests/WebPlatformSubset/contracts/css-retained-effect-values.html‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@
7979
effect.style.removeProperty('filter');
8080
}, 'compound foreground filters preserve authored function order');
8181

82+
test(() => {
83+
effect.style.setProperty('filter', 'blur(max(4px, calc(8px * 0.25)))');
84+
assert_equals(getComputedStyle(effect).getPropertyValue('filter'),
85+
'blur(max(4px, calc(8px * 0.25)))');
86+
effect.style.removeProperty('filter');
87+
}, 'foreground blur preserves nested functional length syntax');
88+
8289
test(() => {
8390
assert_equals(getComputedStyle(effect).getPropertyValue('backdrop-filter'), 'blur(3px)');
8491
}, 'backdrop filter exposes its computed function list');

0 commit comments

Comments
 (0)