Commits:
-
9a7a95dc
by Jonathan Kew at 2026-04-16T09:17:32+02:00
Bug 2009213 - Use local statics for harfbuzz callback pointers, to ensure thread-safe initialization. r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D278945
-
f3289251
by Pier Angelo Vendrame at 2026-04-16T09:17:33+02:00
Bug 1666613 - Do not rely on intl.css for text direction in parsererror. r=dom-core,hsivonen,firefox-style-system-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D244629
7 changed files:
Changes:
dom/xml/nsXMLContentSink.cpp
| ... |
... |
@@ -54,6 +54,7 @@ |
|
54
|
54
|
#include "mozilla/dom/ScriptLoader.h"
|
|
55
|
55
|
#include "mozilla/dom/txMozillaXSLTProcessor.h"
|
|
56
|
56
|
#include "mozilla/dom/nsCSPUtils.h"
|
|
|
57
|
+#include "mozilla/intl/LocaleService.h"
|
|
57
|
58
|
#include "mozilla/CycleCollectedJSContext.h"
|
|
58
|
59
|
#include "mozilla/LoadInfo.h"
|
|
59
|
60
|
#include "mozilla/UseCounter.h"
|
| ... |
... |
@@ -1370,12 +1371,6 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, |
|
1370
|
1371
|
}
|
|
1371
|
1372
|
|
|
1372
|
1373
|
// prepare to set <parsererror> as the document root
|
|
1373
|
|
- rv = HandleProcessingInstruction(
|
|
1374
|
|
- u"xml-stylesheet",
|
|
1375
|
|
- u"href="">\"chrome://global/locale/intl.css\" type=\"text/css\"");
|
|
1376
|
|
- NS_ENSURE_SUCCESS(rv, rv);
|
|
1377
|
|
-
|
|
1378
|
|
- const char16_t* noAtts[] = {0, 0};
|
|
1379
|
1374
|
|
|
1380
|
1375
|
constexpr auto errorNs =
|
|
1381
|
1376
|
u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns;
|
| ... |
... |
@@ -1384,7 +1379,12 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, |
|
1384
|
1379
|
parsererror.Append((char16_t)0xFFFF);
|
|
1385
|
1380
|
parsererror.AppendLiteral("parsererror");
|
|
1386
|
1381
|
|
|
1387
|
|
- rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1, 0);
|
|
|
1382
|
+ const char16_t* dirAttr[] = {u"dir", u"ltr", 0, 0};
|
|
|
1383
|
+ if (intl::LocaleService::GetInstance()->IsAppLocaleRTL() &&
|
|
|
1384
|
+ !mDocument->ShouldResistFingerprinting(RFPTarget::JSLocale)) {
|
|
|
1385
|
+ dirAttr[1] = u"rtl";
|
|
|
1386
|
+ }
|
|
|
1387
|
+ rv = HandleStartElement(parsererror.get(), dirAttr, 0, 2, 0);
|
|
1388
|
1388
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
1389
|
1389
|
|
|
1390
|
1390
|
rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false);
|
| ... |
... |
@@ -1394,6 +1394,7 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, |
|
1394
|
1394
|
sourcetext.Append((char16_t)0xFFFF);
|
|
1395
|
1395
|
sourcetext.AppendLiteral("sourcetext");
|
|
1396
|
1396
|
|
|
|
1397
|
+ const char16_t* noAtts[] = {0, 0};
|
|
1397
|
1398
|
rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1, 0);
|
|
1398
|
1399
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
1399
|
1400
|
|
dom/xml/test/file_bug1666613.xml
dom/xml/test/mochitest.toml
| ... |
... |
@@ -4,6 +4,7 @@ support-files = [ |
|
4
|
4
|
"file_bug293347xslt.xml",
|
|
5
|
5
|
"file_bug343870.xml",
|
|
6
|
6
|
"file_bug691215.xml",
|
|
|
7
|
+ "file_bug1666613.xml",
|
|
7
|
8
|
]
|
|
8
|
9
|
|
|
9
|
10
|
["test_bug232004.xhtml"]
|
| ... |
... |
@@ -19,3 +20,5 @@ skip-if = [ |
|
19
|
20
|
"http2",
|
|
20
|
21
|
"http3",
|
|
21
|
22
|
]
|
|
|
23
|
+
|
|
|
24
|
+["test_bug1666613.html"] |
dom/xml/test/test_bug1666613.html
|
|
1
|
+<!DOCTYPE HTML>
|
|
|
2
|
+<html>
|
|
|
3
|
+<head>
|
|
|
4
|
+ <title>Test for Bug 1666613</title>
|
|
|
5
|
+ <script src="">"/tests/SimpleTest/SimpleTest.js"></script>
|
|
|
6
|
+ <link rel="stylesheet" type="text/css" href="">"/tests/SimpleTest/test.css"/>
|
|
|
7
|
+ <style>iframe { width: 90%; }</style>
|
|
|
8
|
+</head>
|
|
|
9
|
+<body>
|
|
|
10
|
+<a target="_blank" href="">"https://bugzilla.mozilla.org/show_bug.cgi?id=1666613">Mozilla Bug 691215</a>
|
|
|
11
|
+<p id="display"></p>
|
|
|
12
|
+<script class="testbody" type="text/_javascript_">
|
|
|
13
|
+
|
|
|
14
|
+SimpleTest.waitForExplicitFinish();
|
|
|
15
|
+
|
|
|
16
|
+function checkDir(expected) {
|
|
|
17
|
+ return new Promise(resolve => {
|
|
|
18
|
+ let iframe = document.createElement("iframe");
|
|
|
19
|
+ document.body.append(iframe);
|
|
|
20
|
+ iframe.onload = () => {
|
|
|
21
|
+ let parserError = iframe.contentDocument.documentElement;
|
|
|
22
|
+ is(parserError.getAttribute("dir"), expected);
|
|
|
23
|
+ resolve();
|
|
|
24
|
+ };
|
|
|
25
|
+ iframe.src = "file_bug1666613.xml";
|
|
|
26
|
+ });
|
|
|
27
|
+}
|
|
|
28
|
+
|
|
|
29
|
+async function sanityTest() {
|
|
|
30
|
+ await checkDir("ltr");
|
|
|
31
|
+ await pseudoBidiTest();
|
|
|
32
|
+}
|
|
|
33
|
+
|
|
|
34
|
+async function pseudoBidiTest() {
|
|
|
35
|
+ await SpecialPowers.pushPrefEnv({
|
|
|
36
|
+ set: [["intl.l10n.pseudo", "bidi"]]
|
|
|
37
|
+ });
|
|
|
38
|
+ await checkDir("rtl");
|
|
|
39
|
+ SimpleTest.finish();
|
|
|
40
|
+}
|
|
|
41
|
+
|
|
|
42
|
+sanityTest();
|
|
|
43
|
+</script>
|
|
|
44
|
+</body>
|
|
|
45
|
+</html> |
gfx/thebes/gfxHarfBuzzShaper.cpp
| ... |
... |
@@ -1181,9 +1181,6 @@ static void AddOpenTypeFeature(uint32_t aTag, uint32_t aValue, void* aUserArg) { |
|
1181
|
1181
|
* gfxFontShaper override to initialize the text run using HarfBuzz
|
|
1182
|
1182
|
*/
|
|
1183
|
1183
|
|
|
1184
|
|
-static hb_font_funcs_t* sHBFontFuncs = nullptr;
|
|
1185
|
|
-static hb_font_funcs_t* sNominalGlyphFunc = nullptr;
|
|
1186
|
|
-static hb_unicode_funcs_t* sHBUnicodeFuncs = nullptr;
|
|
1187
|
1184
|
MOZ_RUNINIT static const hb_script_t sMathScript =
|
|
1188
|
1185
|
hb_ot_tag_to_script(HB_TAG('m', 'a', 't', 'h'));
|
|
1189
|
1186
|
|
| ... |
... |
@@ -1192,52 +1189,58 @@ bool gfxHarfBuzzShaper::Initialize() { |
|
1192
|
1189
|
// other thread can yet be using it.
|
|
1193
|
1190
|
MOZ_PUSH_IGNORE_THREAD_SAFETY
|
|
1194
|
1191
|
|
|
1195
|
|
- if (!sHBFontFuncs) {
|
|
1196
|
|
- // static function callback pointers, initialized by the first
|
|
1197
|
|
- // harfbuzz shaper used
|
|
1198
|
|
- sHBFontFuncs = hb_font_funcs_create();
|
|
1199
|
|
- hb_font_funcs_set_nominal_glyph_func(sHBFontFuncs, HBGetNominalGlyph,
|
|
1200
|
|
- nullptr, nullptr);
|
|
1201
|
|
- hb_font_funcs_set_nominal_glyphs_func(sHBFontFuncs, HBGetNominalGlyphs,
|
|
1202
|
|
- nullptr, nullptr);
|
|
1203
|
|
- hb_font_funcs_set_variation_glyph_func(sHBFontFuncs, HBGetVariationGlyph,
|
|
1204
|
|
- nullptr, nullptr);
|
|
1205
|
|
- hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs, HBGetGlyphHAdvance,
|
|
1206
|
|
- nullptr, nullptr);
|
|
1207
|
|
- hb_font_funcs_set_glyph_h_advances_func(sHBFontFuncs, HBGetGlyphHAdvances,
|
|
1208
|
|
- nullptr, nullptr);
|
|
1209
|
|
- hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs, HBGetGlyphVAdvance,
|
|
1210
|
|
- nullptr, nullptr);
|
|
1211
|
|
- hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs, HBGetGlyphVOrigin,
|
|
1212
|
|
- nullptr, nullptr);
|
|
1213
|
|
- hb_font_funcs_set_glyph_extents_func(sHBFontFuncs, HBGetGlyphExtents,
|
|
1214
|
|
- nullptr, nullptr);
|
|
1215
|
|
- hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs, HBGetContourPoint,
|
|
|
1192
|
+ // Function callback pointers; these are local statics to ensure thread-safe
|
|
|
1193
|
+ // initialization on first use.
|
|
|
1194
|
+ static hb_font_funcs_t* sHBFontFuncs = [] {
|
|
|
1195
|
+ auto* funcs = hb_font_funcs_create();
|
|
|
1196
|
+ hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr,
|
|
|
1197
|
+ nullptr);
|
|
|
1198
|
+ hb_font_funcs_set_nominal_glyphs_func(funcs, HBGetNominalGlyphs, nullptr,
|
|
|
1199
|
+ nullptr);
|
|
|
1200
|
+ hb_font_funcs_set_variation_glyph_func(funcs, HBGetVariationGlyph, nullptr,
|
|
|
1201
|
+ nullptr);
|
|
|
1202
|
+ hb_font_funcs_set_glyph_h_advance_func(funcs, HBGetGlyphHAdvance, nullptr,
|
|
|
1203
|
+ nullptr);
|
|
|
1204
|
+ hb_font_funcs_set_glyph_h_advances_func(funcs, HBGetGlyphHAdvances, nullptr,
|
|
|
1205
|
+ nullptr);
|
|
|
1206
|
+ hb_font_funcs_set_glyph_v_advance_func(funcs, HBGetGlyphVAdvance, nullptr,
|
|
|
1207
|
+ nullptr);
|
|
|
1208
|
+ hb_font_funcs_set_glyph_v_origin_func(funcs, HBGetGlyphVOrigin, nullptr,
|
|
|
1209
|
+ nullptr);
|
|
|
1210
|
+ hb_font_funcs_set_glyph_extents_func(funcs, HBGetGlyphExtents, nullptr,
|
|
|
1211
|
+ nullptr);
|
|
|
1212
|
+ hb_font_funcs_set_glyph_contour_point_func(funcs, HBGetContourPoint,
|
|
1216
|
1213
|
nullptr, nullptr);
|
|
1217
|
|
- hb_font_funcs_set_glyph_h_kerning_func(sHBFontFuncs, HBGetHKerning, nullptr,
|
|
|
1214
|
+ hb_font_funcs_set_glyph_h_kerning_func(funcs, HBGetHKerning, nullptr,
|
|
1218
|
1215
|
nullptr);
|
|
1219
|
|
- hb_font_funcs_make_immutable(sHBFontFuncs);
|
|
1220
|
|
-
|
|
1221
|
|
- sNominalGlyphFunc = hb_font_funcs_create();
|
|
1222
|
|
- hb_font_funcs_set_nominal_glyph_func(sNominalGlyphFunc, HBGetNominalGlyph,
|
|
1223
|
|
- nullptr, nullptr);
|
|
1224
|
|
- hb_font_funcs_make_immutable(sNominalGlyphFunc);
|
|
1225
|
|
-
|
|
1226
|
|
- sHBUnicodeFuncs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty());
|
|
1227
|
|
- hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs, HBGetMirroring,
|
|
1228
|
|
- nullptr, nullptr);
|
|
1229
|
|
- hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript, nullptr,
|
|
1230
|
|
- nullptr);
|
|
1231
|
|
- hb_unicode_funcs_set_general_category_func(
|
|
1232
|
|
- sHBUnicodeFuncs, HBGetGeneralCategory, nullptr, nullptr);
|
|
1233
|
|
- hb_unicode_funcs_set_combining_class_func(
|
|
1234
|
|
- sHBUnicodeFuncs, HBGetCombiningClass, nullptr, nullptr);
|
|
1235
|
|
- hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs, HBUnicodeCompose,
|
|
1236
|
|
- nullptr, nullptr);
|
|
1237
|
|
- hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs, HBUnicodeDecompose,
|
|
1238
|
|
- nullptr, nullptr);
|
|
1239
|
|
- hb_unicode_funcs_make_immutable(sHBUnicodeFuncs);
|
|
1240
|
|
- }
|
|
|
1216
|
+ hb_font_funcs_make_immutable(funcs);
|
|
|
1217
|
+ return funcs;
|
|
|
1218
|
+ }();
|
|
|
1219
|
+
|
|
|
1220
|
+ static hb_font_funcs_t* sNominalGlyphFunc = [] {
|
|
|
1221
|
+ auto* funcs = hb_font_funcs_create();
|
|
|
1222
|
+ hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr,
|
|
|
1223
|
+ nullptr);
|
|
|
1224
|
+ hb_font_funcs_make_immutable(funcs);
|
|
|
1225
|
+ return funcs;
|
|
|
1226
|
+ }();
|
|
|
1227
|
+
|
|
|
1228
|
+ static hb_unicode_funcs_t* sHBUnicodeFuncs = [] {
|
|
|
1229
|
+ auto* funcs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty());
|
|
|
1230
|
+ hb_unicode_funcs_set_mirroring_func(funcs, HBGetMirroring, nullptr,
|
|
|
1231
|
+ nullptr);
|
|
|
1232
|
+ hb_unicode_funcs_set_script_func(funcs, HBGetScript, nullptr, nullptr);
|
|
|
1233
|
+ hb_unicode_funcs_set_general_category_func(funcs, HBGetGeneralCategory,
|
|
|
1234
|
+ nullptr, nullptr);
|
|
|
1235
|
+ hb_unicode_funcs_set_combining_class_func(funcs, HBGetCombiningClass,
|
|
|
1236
|
+ nullptr, nullptr);
|
|
|
1237
|
+ hb_unicode_funcs_set_compose_func(funcs, HBUnicodeCompose, nullptr,
|
|
|
1238
|
+ nullptr);
|
|
|
1239
|
+ hb_unicode_funcs_set_decompose_func(funcs, HBUnicodeDecompose, nullptr,
|
|
|
1240
|
+ nullptr);
|
|
|
1241
|
+ hb_unicode_funcs_make_immutable(funcs);
|
|
|
1242
|
+ return funcs;
|
|
|
1243
|
+ }();
|
|
1241
|
1244
|
|
|
1242
|
1245
|
gfxFontEntry* entry = mFont->GetFontEntry();
|
|
1243
|
1246
|
if (!mUseFontGetGlyph) {
|
| ... |
... |
@@ -1280,11 +1283,10 @@ bool gfxHarfBuzzShaper::Initialize() { |
|
1280
|
1283
|
hb_buffer_set_cluster_level(mBuffer,
|
|
1281
|
1284
|
HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS);
|
|
1282
|
1285
|
|
|
1283
|
|
- auto* funcs =
|
|
1284
|
|
- mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '))
|
|
1285
|
|
- ? sNominalGlyphFunc
|
|
1286
|
|
- : sHBFontFuncs;
|
|
1287
|
|
- mHBFont = CreateHBFont(mFont, funcs, this);
|
|
|
1286
|
+ bool isCFF =
|
|
|
1287
|
+ mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' '));
|
|
|
1288
|
+ auto* funcs = isCFF ? sNominalGlyphFunc : sHBFontFuncs;
|
|
|
1289
|
+ mHBFont = CreateHBFont(mFont, funcs, this, isCFF);
|
|
1288
|
1290
|
|
|
1289
|
1291
|
MOZ_POP_THREAD_SAFETY
|
|
1290
|
1292
|
|
| ... |
... |
@@ -1293,12 +1295,13 @@ bool gfxHarfBuzzShaper::Initialize() { |
|
1293
|
1295
|
|
|
1294
|
1296
|
hb_font_t* gfxHarfBuzzShaper::CreateHBFont(gfxFont* aFont,
|
|
1295
|
1297
|
hb_font_funcs_t* aFontFuncs,
|
|
1296
|
|
- void* aCallbackData) {
|
|
|
1298
|
+ void* aCallbackData,
|
|
|
1299
|
+ bool aCreateSubfont) {
|
|
1297
|
1300
|
auto face(aFont->GetFontEntry()->GetHBFace());
|
|
1298
|
1301
|
hb_font_t* result = hb_font_create(face);
|
|
1299
|
1302
|
|
|
1300
|
1303
|
if (aFontFuncs && aCallbackData) {
|
|
1301
|
|
- if (aFontFuncs == sNominalGlyphFunc) {
|
|
|
1304
|
+ if (aCreateSubfont) {
|
|
1302
|
1305
|
hb_font_t* subfont = hb_font_create_sub_font(result);
|
|
1303
|
1306
|
hb_font_destroy(result);
|
|
1304
|
1307
|
result = subfont;
|
gfx/thebes/gfxHarfBuzzShaper.h
| ... |
... |
@@ -103,7 +103,8 @@ class gfxHarfBuzzShaper : public gfxFontShaper { |
|
103
|
103
|
// bounds, etc; if not, the built-in hb_ot font functions will be used.
|
|
104
|
104
|
static hb_font_t* CreateHBFont(gfxFont* aFont,
|
|
105
|
105
|
hb_font_funcs_t* aFontFuncs = nullptr,
|
|
106
|
|
- void* aCallbackData = nullptr);
|
|
|
106
|
+ void* aCallbackData = nullptr,
|
|
|
107
|
+ bool aCreateSubfont = false);
|
|
107
|
108
|
|
|
108
|
109
|
protected:
|
|
109
|
110
|
// Initializes the shaper and returns whether this was successful.
|
layout/style/res/ua.css
| ... |
... |
@@ -434,6 +434,10 @@ parsererror|parsererror { |
|
434
|
434
|
color: black;
|
|
435
|
435
|
}
|
|
436
|
436
|
|
|
|
437
|
+parsererror|parsererror[dir="rtl"] {
|
|
|
438
|
+ direction: rtl;
|
|
|
439
|
+}
|
|
|
440
|
+
|
|
437
|
441
|
parsererror|sourcetext {
|
|
438
|
442
|
display: block;
|
|
439
|
443
|
white-space: pre;
|
| ... |
... |
@@ -443,6 +447,7 @@ parsererror|sourcetext { |
|
443
|
447
|
color: red;
|
|
444
|
448
|
font-weight: bold;
|
|
445
|
449
|
font-size: 12pt;
|
|
|
450
|
+ direction: ltr;
|
|
446
|
451
|
}
|
|
447
|
452
|
|
|
448
|
453
|
/* Custom content container in the CanvasFrame, positioned on top of everything
|
|