Skip to content

Commit 7f98fc1

Browse files
Do not decode CSS escapes in background url() in JS
The native CSS parser treats a backslash in url() as an ordinary character. The JS parser now does the same, so both parsers give the same result.
1 parent 6c4941c commit 7f98fc1

2 files changed

Lines changed: 17 additions & 59 deletions

File tree

‎packages/react-native/Libraries/StyleSheet/__tests__/processBackgroundImage-itest.js‎

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,16 +1377,24 @@ describe('processBackgroundImage', () => {
13771377
});
13781378
}
13791379

1380-
for (const [name, backgroundImage, uri] of [
1381-
['an escaped parenthesis', 'url(a\\)b.png)', 'a)b.png'],
1382-
['an escaped quote in a quoted url', 'url("a\\"b.png")', 'a"b.png'],
1383-
['a hex escape', 'url(a\\20 b.png)', 'a b.png'],
1384-
['a missing closing parenthesis', 'url(a.png', 'a.png'],
1380+
it('should parse a url with a missing closing parenthesis', () => {
1381+
expect(processBackgroundImage('url(a.png')).toEqual([
1382+
{type: 'url', uri: 'a.png'},
1383+
]);
1384+
});
1385+
1386+
it('should keep a backslash in a quoted url', () => {
1387+
expect(processBackgroundImage('url("a\\20b.png")')).toEqual([
1388+
{type: 'url', uri: 'a\\20b.png'},
1389+
]);
1390+
});
1391+
1392+
for (const [name, backgroundImage] of [
1393+
['an escaped parenthesis', 'url(a\\)b.png)'],
1394+
['an escaped quote in a quoted url', 'url("a\\"b.png")'],
13851395
]) {
1386-
it(`should parse a url with ${name}`, () => {
1387-
expect(processBackgroundImage(backgroundImage)).toEqual([
1388-
{type: 'url', uri},
1389-
]);
1396+
it(`should return empty for ${name}`, () => {
1397+
expect(processBackgroundImage(backgroundImage)).toEqual([]);
13901398
});
13911399
}
13921400
});

‎packages/react-native/Libraries/StyleSheet/processBackgroundImage.js‎

Lines changed: 0 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -403,20 +403,6 @@ function parseURLFunctionBody(input: string): ?string {
403403
i++;
404404
break;
405405
}
406-
if (char === '\\') {
407-
if (i + 1 < input.length && isCSSNewline(input[i + 1])) {
408-
// An escaped newline is skipped.
409-
i += 2;
410-
continue;
411-
}
412-
if (i + 1 >= input.length) {
413-
return null;
414-
}
415-
const [codePoint, length] = consumeCSSEscape(input, i + 1);
416-
uri += codePoint;
417-
i += 1 + length;
418-
continue;
419-
}
420406
uri += char;
421407
i++;
422408
}
@@ -448,49 +434,13 @@ function parseURLFunctionBody(input: string): ?string {
448434
) {
449435
return null;
450436
}
451-
if (char === '\\') {
452-
if (i + 1 >= input.length || isCSSNewline(input[i + 1])) {
453-
return null;
454-
}
455-
const [codePoint, length] = consumeCSSEscape(input, i + 1);
456-
uri += codePoint;
457-
i += 1 + length;
458-
continue;
459-
}
460437
uri += char;
461438
i++;
462439
}
463440
// A missing `)` at the end is a parse error, but the url is kept.
464441
return uri;
465442
}
466443

467-
// https://www.w3.org/TR/css-syntax-3/#consume-escaped-code-point
468-
// `start` is the index after the backslash. Returns the code point and the
469-
// number of characters it used.
470-
function consumeCSSEscape(input: string, start: number): [string, number] {
471-
let i = start;
472-
let hex = '';
473-
while (i < input.length && hex.length < 6 && /[0-9a-fA-F]/.test(input[i])) {
474-
hex += input[i];
475-
i++;
476-
}
477-
if (hex.length === 0) {
478-
return [input[start], 1];
479-
}
480-
if (i < input.length && isCSSWhitespace(input[i])) {
481-
i++;
482-
}
483-
let codePoint = parseInt(hex, 16);
484-
if (
485-
codePoint === 0 ||
486-
(codePoint >= 0xd800 && codePoint <= 0xdfff) ||
487-
codePoint > 0x10ffff
488-
) {
489-
codePoint = 0xfffd;
490-
}
491-
return [String.fromCodePoint(codePoint), i - start];
492-
}
493-
494444
function parseRadialGradientCSSString(
495445
gradientContent: string,
496446
): RadialGradientBackgroundImage | null {

0 commit comments

Comments
 (0)