Pier Angelo Vendrame pushed to branch mullvad-browser-140.10.0esr-15.0-1 at The Tor Project / Applications / Mullvad Browser 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: - dom/xml/nsXMLContentSink.cpp - + dom/xml/test/file_bug1666613.xml - dom/xml/test/mochitest.toml - + dom/xml/test/test_bug1666613.html - gfx/thebes/gfxHarfBuzzShaper.cpp - gfx/thebes/gfxHarfBuzzShaper.h - layout/style/res/ua.css Changes: ===================================== dom/xml/nsXMLContentSink.cpp ===================================== @@ -54,6 +54,7 @@ #include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/txMozillaXSLTProcessor.h" #include "mozilla/dom/nsCSPUtils.h" +#include "mozilla/intl/LocaleService.h" #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/LoadInfo.h" #include "mozilla/UseCounter.h" @@ -1370,12 +1371,6 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, } // prepare to set <parsererror> as the document root - rv = HandleProcessingInstruction( - u"xml-stylesheet", - u"href=\"chrome://global/locale/intl.css\" type=\"text/css\""); - NS_ENSURE_SUCCESS(rv, rv); - - const char16_t* noAtts[] = {0, 0}; constexpr auto errorNs = u"http://www.mozilla.org/newlayout/xml/parsererror.xml"_ns; @@ -1384,7 +1379,12 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, parsererror.Append((char16_t)0xFFFF); parsererror.AppendLiteral("parsererror"); - rv = HandleStartElement(parsererror.get(), noAtts, 0, (uint32_t)-1, 0); + const char16_t* dirAttr[] = {u"dir", u"ltr", 0, 0}; + if (intl::LocaleService::GetInstance()->IsAppLocaleRTL() && + !mDocument->ShouldResistFingerprinting(RFPTarget::JSLocale)) { + dirAttr[1] = u"rtl"; + } + rv = HandleStartElement(parsererror.get(), dirAttr, 0, 2, 0); NS_ENSURE_SUCCESS(rv, rv); rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText), false); @@ -1394,6 +1394,7 @@ nsXMLContentSink::ReportError(const char16_t* aErrorText, sourcetext.Append((char16_t)0xFFFF); sourcetext.AppendLiteral("sourcetext"); + const char16_t* noAtts[] = {0, 0}; rv = HandleStartElement(sourcetext.get(), noAtts, 0, (uint32_t)-1, 0); NS_ENSURE_SUCCESS(rv, rv); ===================================== dom/xml/test/file_bug1666613.xml ===================================== @@ -0,0 +1 @@ +<invalid ===================================== dom/xml/test/mochitest.toml ===================================== @@ -4,6 +4,7 @@ support-files = [ "file_bug293347xslt.xml", "file_bug343870.xml", "file_bug691215.xml", + "file_bug1666613.xml", ] ["test_bug232004.xhtml"] @@ -19,3 +20,5 @@ skip-if = [ "http2", "http3", ] + +["test_bug1666613.html"] ===================================== dom/xml/test/test_bug1666613.html ===================================== @@ -0,0 +1,45 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test for Bug 1666613</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <style>iframe { width: 90%; }</style> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1666613">Mozilla Bug 691215</a> +<p id="display"></p> +<script class="testbody" type="text/javascript"> + +SimpleTest.waitForExplicitFinish(); + +function checkDir(expected) { + return new Promise(resolve => { + let iframe = document.createElement("iframe"); + document.body.append(iframe); + iframe.onload = () => { + let parserError = iframe.contentDocument.documentElement; + is(parserError.getAttribute("dir"), expected); + resolve(); + }; + iframe.src = "file_bug1666613.xml"; + }); +} + +async function sanityTest() { + await checkDir("ltr"); + await pseudoBidiTest(); +} + +async function pseudoBidiTest() { + await SpecialPowers.pushPrefEnv({ + set: [["intl.l10n.pseudo", "bidi"]] + }); + await checkDir("rtl"); + SimpleTest.finish(); +} + +sanityTest(); +</script> +</body> +</html> ===================================== gfx/thebes/gfxHarfBuzzShaper.cpp ===================================== @@ -1181,9 +1181,6 @@ static void AddOpenTypeFeature(uint32_t aTag, uint32_t aValue, void* aUserArg) { * gfxFontShaper override to initialize the text run using HarfBuzz */ -static hb_font_funcs_t* sHBFontFuncs = nullptr; -static hb_font_funcs_t* sNominalGlyphFunc = nullptr; -static hb_unicode_funcs_t* sHBUnicodeFuncs = nullptr; MOZ_RUNINIT static const hb_script_t sMathScript = hb_ot_tag_to_script(HB_TAG('m', 'a', 't', 'h')); @@ -1192,52 +1189,58 @@ bool gfxHarfBuzzShaper::Initialize() { // other thread can yet be using it. MOZ_PUSH_IGNORE_THREAD_SAFETY - if (!sHBFontFuncs) { - // static function callback pointers, initialized by the first - // harfbuzz shaper used - sHBFontFuncs = hb_font_funcs_create(); - hb_font_funcs_set_nominal_glyph_func(sHBFontFuncs, HBGetNominalGlyph, - nullptr, nullptr); - hb_font_funcs_set_nominal_glyphs_func(sHBFontFuncs, HBGetNominalGlyphs, - nullptr, nullptr); - hb_font_funcs_set_variation_glyph_func(sHBFontFuncs, HBGetVariationGlyph, - nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs, HBGetGlyphHAdvance, - nullptr, nullptr); - hb_font_funcs_set_glyph_h_advances_func(sHBFontFuncs, HBGetGlyphHAdvances, - nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs, HBGetGlyphVAdvance, - nullptr, nullptr); - hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs, HBGetGlyphVOrigin, - nullptr, nullptr); - hb_font_funcs_set_glyph_extents_func(sHBFontFuncs, HBGetGlyphExtents, - nullptr, nullptr); - hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs, HBGetContourPoint, + // Function callback pointers; these are local statics to ensure thread-safe + // initialization on first use. + static hb_font_funcs_t* sHBFontFuncs = [] { + auto* funcs = hb_font_funcs_create(); + hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr, + nullptr); + hb_font_funcs_set_nominal_glyphs_func(funcs, HBGetNominalGlyphs, nullptr, + nullptr); + hb_font_funcs_set_variation_glyph_func(funcs, HBGetVariationGlyph, nullptr, + nullptr); + hb_font_funcs_set_glyph_h_advance_func(funcs, HBGetGlyphHAdvance, nullptr, + nullptr); + hb_font_funcs_set_glyph_h_advances_func(funcs, HBGetGlyphHAdvances, nullptr, + nullptr); + hb_font_funcs_set_glyph_v_advance_func(funcs, HBGetGlyphVAdvance, nullptr, + nullptr); + hb_font_funcs_set_glyph_v_origin_func(funcs, HBGetGlyphVOrigin, nullptr, + nullptr); + hb_font_funcs_set_glyph_extents_func(funcs, HBGetGlyphExtents, nullptr, + nullptr); + hb_font_funcs_set_glyph_contour_point_func(funcs, HBGetContourPoint, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func(sHBFontFuncs, HBGetHKerning, nullptr, + hb_font_funcs_set_glyph_h_kerning_func(funcs, HBGetHKerning, nullptr, nullptr); - hb_font_funcs_make_immutable(sHBFontFuncs); - - sNominalGlyphFunc = hb_font_funcs_create(); - hb_font_funcs_set_nominal_glyph_func(sNominalGlyphFunc, HBGetNominalGlyph, - nullptr, nullptr); - hb_font_funcs_make_immutable(sNominalGlyphFunc); - - sHBUnicodeFuncs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty()); - hb_unicode_funcs_set_mirroring_func(sHBUnicodeFuncs, HBGetMirroring, - nullptr, nullptr); - hb_unicode_funcs_set_script_func(sHBUnicodeFuncs, HBGetScript, nullptr, - nullptr); - hb_unicode_funcs_set_general_category_func( - sHBUnicodeFuncs, HBGetGeneralCategory, nullptr, nullptr); - hb_unicode_funcs_set_combining_class_func( - sHBUnicodeFuncs, HBGetCombiningClass, nullptr, nullptr); - hb_unicode_funcs_set_compose_func(sHBUnicodeFuncs, HBUnicodeCompose, - nullptr, nullptr); - hb_unicode_funcs_set_decompose_func(sHBUnicodeFuncs, HBUnicodeDecompose, - nullptr, nullptr); - hb_unicode_funcs_make_immutable(sHBUnicodeFuncs); - } + hb_font_funcs_make_immutable(funcs); + return funcs; + }(); + + static hb_font_funcs_t* sNominalGlyphFunc = [] { + auto* funcs = hb_font_funcs_create(); + hb_font_funcs_set_nominal_glyph_func(funcs, HBGetNominalGlyph, nullptr, + nullptr); + hb_font_funcs_make_immutable(funcs); + return funcs; + }(); + + static hb_unicode_funcs_t* sHBUnicodeFuncs = [] { + auto* funcs = hb_unicode_funcs_create(hb_unicode_funcs_get_empty()); + hb_unicode_funcs_set_mirroring_func(funcs, HBGetMirroring, nullptr, + nullptr); + hb_unicode_funcs_set_script_func(funcs, HBGetScript, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func(funcs, HBGetGeneralCategory, + nullptr, nullptr); + hb_unicode_funcs_set_combining_class_func(funcs, HBGetCombiningClass, + nullptr, nullptr); + hb_unicode_funcs_set_compose_func(funcs, HBUnicodeCompose, nullptr, + nullptr); + hb_unicode_funcs_set_decompose_func(funcs, HBUnicodeDecompose, nullptr, + nullptr); + hb_unicode_funcs_make_immutable(funcs); + return funcs; + }(); gfxFontEntry* entry = mFont->GetFontEntry(); if (!mUseFontGetGlyph) { @@ -1280,11 +1283,10 @@ bool gfxHarfBuzzShaper::Initialize() { hb_buffer_set_cluster_level(mBuffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); - auto* funcs = - mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' ')) - ? sNominalGlyphFunc - : sHBFontFuncs; - mHBFont = CreateHBFont(mFont, funcs, this); + bool isCFF = + mFont->GetFontEntry()->HasFontTable(TRUETYPE_TAG('C', 'F', 'F', ' ')); + auto* funcs = isCFF ? sNominalGlyphFunc : sHBFontFuncs; + mHBFont = CreateHBFont(mFont, funcs, this, isCFF); MOZ_POP_THREAD_SAFETY @@ -1293,12 +1295,13 @@ bool gfxHarfBuzzShaper::Initialize() { hb_font_t* gfxHarfBuzzShaper::CreateHBFont(gfxFont* aFont, hb_font_funcs_t* aFontFuncs, - void* aCallbackData) { + void* aCallbackData, + bool aCreateSubfont) { auto face(aFont->GetFontEntry()->GetHBFace()); hb_font_t* result = hb_font_create(face); if (aFontFuncs && aCallbackData) { - if (aFontFuncs == sNominalGlyphFunc) { + if (aCreateSubfont) { hb_font_t* subfont = hb_font_create_sub_font(result); hb_font_destroy(result); result = subfont; ===================================== gfx/thebes/gfxHarfBuzzShaper.h ===================================== @@ -103,7 +103,8 @@ class gfxHarfBuzzShaper : public gfxFontShaper { // bounds, etc; if not, the built-in hb_ot font functions will be used. static hb_font_t* CreateHBFont(gfxFont* aFont, hb_font_funcs_t* aFontFuncs = nullptr, - void* aCallbackData = nullptr); + void* aCallbackData = nullptr, + bool aCreateSubfont = false); protected: // Initializes the shaper and returns whether this was successful. ===================================== layout/style/res/ua.css ===================================== @@ -434,6 +434,10 @@ parsererror|parsererror { color: black; } +parsererror|parsererror[dir="rtl"] { + direction: rtl; +} + parsererror|sourcetext { display: block; white-space: pre; @@ -443,6 +447,7 @@ parsererror|sourcetext { color: red; font-weight: bold; font-size: 12pt; + direction: ltr; } /* Custom content container in the CanvasFrame, positioned on top of everything View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/054... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/mullvad-browser/-/compare/054... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help
participants (1)
-
Pier Angelo Vendrame (@pierov)