tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit cd0b57aa93671dc679e42a1dbbc098308f9f0afa
parent 4c4be6154de1876375751d395f3a5082eaeb6a13
Author: Atila Butkovits <abutkovits@mozilla.com>
Date:   Mon,  5 Jan 2026 14:51:43 +0200

Revert "Bug 1007090 - Part 4: Hardcode mathfontUnicode.properties. r=emilio,layout-reviewers" for causing failures complaining about mathfontUnicode.

This reverts commit a0b5057dab54973a089db7b096bea12f6a252661.

Revert "Bug 1007090 - Part 3: Rename nsPropertiesTable to nsUnicodeTable. r=emilio,layout-reviewers"

This reverts commit bfab0e2d2e480429b03b6ee0b6640a6adfb20902.

Revert "Bug 1007090 - Part 2: Remove support for external fonts in nsPropertiesTable. r=emilio,layout-reviewers"

This reverts commit dc1f434489c52d0aead430c0104ea85602361e24.

Revert "Bug 1007090 - Part 1: Fix size 0 of U+21A4 in mathfontUnicode.properties. r=emilio,layout-reviewers"

This reverts commit 9b9886bad6e007b5cff2312c00a74777df07ff95.

Diffstat:
Mlayout/mathml/mathfont.properties | 16++++++++++++++++
Alayout/mathml/mathfontUnicode.properties | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlayout/mathml/moz.build | 1+
Mlayout/mathml/nsMathMLChar.cpp | 331+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mlayout/mathml/nsMathMLChar.h | 25+++++++++++++++++--------
5 files changed, 339 insertions(+), 126 deletions(-)

diff --git a/layout/mathml/mathfont.properties b/layout/mathml/mathfont.properties @@ -1359,3 +1359,19 @@ operator.\uFE35.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal operator.\uFE36.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # &UnderParenthesis; (MathML 2.0) operator.\uFE37.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # &OverBrace; (MathML 2.0) operator.\uFE38.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # &UnderBrace; (MathML 2.0) + + +################################################################################## +# DOCUMENTATION ON HOW TO SETUP THE PROPERTY FILE ASSOCIATED TO EACH FONT +# More fonts can be supported for stretchy characters by setting up mathfont +# property files as described below. +# +# Each font should have its set of glyph data. For example, the glyph data for +# the "Symbol" font and the "MT Extra" font are in "mathfontSymbol.properties" +# and "mathfontMTExtra.properties", respectively. The font property file is a +# set of all the stretchy MathML characters that can be rendered with that font +# using larger and/or partial glyphs. Each stretchy character is associated to +# a list in the font property file which gives, in that order, the 4 partial +# glyphs: top (or left), middle, bottom (or right), glue; and the variants of +# bigger sizes (if any). A position that is not relevant to a particular character +# is indicated there with the UNICODE REPLACEMENT CHARACTER 0xFFFD. diff --git a/layout/mathml/mathfontUnicode.properties b/layout/mathml/mathfontUnicode.properties @@ -0,0 +1,92 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# LOCALIZATION NOTE: FILE +# Do not translate anything in this file + +# This file contains the list of all stretchy MathML chars that +# can be rendered using only Unicode code points. + +# [ T/L | M | B/R | G | size0 ... size{N-1} ] +\u0028 = \u239B\uFFFD\u239D\u239C\u0028 # ( +\u0029 = \u239E\uFFFD\u23A0\u239F\u0029 # ) +\u005B = \u23A1\uFFFD\u23A3\u23A2\u005B # [ +\u005D = \u23A4\uFFFD\u23A6\u23A5\u005D # ] +\u007B = \u23A7\u23A8\u23A9\u23AA\u007B # { +\u007C = \uFFFD\uFFFD\uFFFD\u007C\u007C # | +\u007D = \u23AB\u23AC\u23AD\u23AA\u007D # } + +# OverBar is stretched with U+0305 COMBINING OVERLINE which "connects on left and right" +\u00AF = \uFFFD\uFFFD\uFFFD\u0305\u00AF # OverBar +#\u0305 doesn't appear to be referenced by the MathML spec +\u203E = \uFFFD\uFFFD\uFFFD\u0305\u00AF # overline +\u0332 = \uFFFD\uFFFD\uFFFD\u0332\u0332 # COMBINING LOW LINE, UnderBar +\u005F = \uFFFD\uFFFD\uFFFD\u0332\u0332 # _ low line +\u003D = \uFFFD\uFFFD\uFFFD\u003D\u003D # = equal sign + +\u2016 = \uFFFD\uFFFD\uFFFD\u2016\u2016 # DOUBLE VERTICAL LINE, Vert, Verbar + +\u2190 = \u2190\uFFFD\uFFFD\u23AF\u2190\u27F5 # LeftArrow, larr, leftarrow +\u2191 = \u2191\uFFFD\uFFFD\u23D0\u2191 # UpArrow, uarr, uparrow +\u2192 = \uFFFD\uFFFD\u2192\u23AF\u2192\u27F6 # RightArrow, rarr, rightarrow +\u2193 = \uFFFD\uFFFD\u2193\u23D0\u2193 # DownArrow, darr, downarrow +\u2194 = \u2190\uFFFD\u2192\u23AF\u2194\u27F7 # LeftRightArrow, harr, leftrightarrow +\u2195 = \u2191\uFFFD\u2193\u23D0\u2195 # UpDownArrow, updownarrow, varr + +# For STIXGeneral U+22A2/U+22A3 RIGHT/LEFT TACK are different heights to U+23AF. +# Could use LONG RIGHT/LEFT TACK instead, but STIXNonUnicode provides +# E0B6 stix-maps-to-relation tail +#\u21A4 = \u2190\uFFFD\u27DE\u23AF\u21A6\u27FB # LeftTeeArrow, mapstoleft +#\u21A6 = \u27DD\uFFFD\u2192\u23AF\u21A6\u27FC # RightTeeArrow, map, mapsto +#\u295A = \u21BC\uFFFD\u27DE\u23AF\u295A # LeftTeeVector +#\u295B = \u27DD\uFFFD\u21C0\u23AF\u295B # RIGHTWARDS HARPOON WITH BARB UP FROM BAR, RightTeeVector +#\u295E = \u21BD\uFFFD\u27DE\u23AF\u295E # DownLeftTeeVector +#\u295F = \u27DD\uFFFD\u21C1\u23AF\u295F # RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR, DownRightTeeVector +# Cambria Math does not have U+27DD/U+27DE +\u21A4 = \u2190\uFFFD\u22A3\u23AF\u21A6\u27FB # LeftTeeArrow, mapstoleft +\u21A6 = \u22A2\uFFFD\u2192\u23AF\u21A6\u27FC # RightTeeArrow, map, mapsto +\u295A = \u21BC\uFFFD\u22A3\u23AF\u295A # LeftTeeVector +\u295B = \u22A2\uFFFD\u21C0\u23AF\u295B # RIGHTWARDS HARPOON WITH BARB UP FROM BAR, RightTeeVector +\u295E = \u21BD\uFFFD\u22A3\u23AF\u295E # DownLeftTeeVector +\u295F = \u22A2\uFFFD\u21C1\u23AF\u295F # RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR, DownRightTeeVector + +\u21C0 = \uFFFD\uFFFD\u21C0\u23AF\u21C0 # RightVector, rharu, rightharpoonup +\u21C1 = \uFFFD\uFFFD\u21C1\u23AF\u21C1 # DownRightVector, rhard, rightharpoon down +\u21BC = \u21BC\uFFFD\uFFFD\u23AF\u21BC # LeftVector, leftharpoonup, lharu +\u21BD = \u21BD\uFFFD\uFFFD\u23AF\u21BD # DownLeftVector, leftharpoondown, lhard +\u21D0 = \uFFFD\uFFFD\uFFFD\uFFFD\u21D0\u27F8 # DoubleLeftArrow, Leftarrow, lArr +\u21D2 = \uFFFD\uFFFD\uFFFD\uFFFD\u21D2\u27F9 # DoubleRightArrow, Implies, Rightarro +\u21D4 = \uFFFD\uFFFD\uFFFD\uFFFD\u21D4\u27FA # DoubleLeftRightArrow, Leftrightarrow, hArr, iff + +# \u221A radical may be made from RADICAL SYMBOL BOTTOM U+23B7 but few fonts +# support this character and it is not clear what the appropriate vertical +# glue whould be. + +\u2223 = \uFFFD\uFFFD\uFFFD\u2223\u2223 # VerticalBar, mid +\u2225 = \uFFFD\uFFFD\uFFFD\u2225\u2225 # DoubleVerticalBar, par, parallel + +# If fonts have U+23AE INTEGRAL EXTENSION: +# (STIXSize1, Cambria Math, DejaVu Sans/Serif, Apple's Symbol) +\u222B = \u2320\uFFFD\u2321\u23AE\u222B # Integral, int +# Many fonts don't have U+23AE. For these fonts, a rule can be used as glue: +# \u222B = \u2320\uFFFD\u2321\uFFFD\u222B # Integral, int + +# Using parts of [ and ] (could use box drawings instead) +\u2308 = \u23A1\uFFFD\uFFFD\u23A2\u2308 # LeftCeiling, lceil +\u2309 = \u23A4\uFFFD\uFFFD\u23A5\u2309 # RightCeiling, rceil +\u230A = \uFFFD\uFFFD\u23A3\u23A2\u230A # LeftFloor, lfloor +\u230B = \uFFFD\uFFFD\u23A6\u23A5\u230B # RightFloor, rfloor + +# Support for l/r moustache from the parts of lbrace { and rbrace } +\u23B0 = \u23A7\uFFFD\u23AD\u23AA\u23B0 # lmoustache, lmoust +\u23B1 = \u23AB\uFFFD\u23A9\u23AA\u23B1 # rmoustache, rmoust + +# Using normal arrows as heads instead of long arrows for the sake of +# Apple's Symbol font. +\u27F5 = \u2190\uFFFD\uFFFD\u23AF\u27F5 # LongLeftArrow +\u27F6 = \uFFFD\uFFFD\u2192\u23AF\u27F6 # LongRightArrow +\u27F7 = \u2190\uFFFD\u2192\u23AF\u27F7 # LongLeftRightArrow + +\u294E = \u21BC\uFFFD\u21C0\u23AF\u294E #LEFT BARB UP RIGHT BARB UP HARPOON, LeftRightVector +\u2950 = \u21BD\uFFFD\u21C1\u23AF\u2950 #LEFT BARB DOWN RIGHT BARB DOWN HARPOON , DownLeftRightVector diff --git a/layout/mathml/moz.build b/layout/mathml/moz.build @@ -55,4 +55,5 @@ JAR_MANIFESTS += ["jar.mn"] RESOURCE_FILES.fonts += [ "mathfont.properties", + "mathfontUnicode.properties", ] diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp @@ -12,7 +12,6 @@ #include "gfxMathTable.h" #include "gfxTextRun.h" #include "gfxUtils.h" -#include "mozilla/BinarySearch.h" #include "mozilla/ComputedStyle.h" #include "mozilla/LookAndFeel.h" #include "mozilla/MathAlgorithms.h" @@ -32,6 +31,7 @@ #include "nsIFrame.h" #include "nsIObserver.h" #include "nsIObserverService.h" +#include "nsIPersistentProperties2.h" #include "nsLayoutUtils.h" #include "nsMathMLOperators.h" #include "nsNetUtil.h" @@ -56,7 +56,7 @@ static void NormalizeDefaultFont(nsFont& aFont, float aFontSizeInflation) { } // ----------------------------------------------------------------------------- -static const nsGlyphCode kNullGlyph = {{0}, false}; +static const nsGlyphCode kNullGlyph = {{{0, 0}}, 0}; // ----------------------------------------------------------------------------- // nsGlyphTable is a class that provides an interface for accessing glyphs @@ -67,7 +67,7 @@ static const nsGlyphCode kNullGlyph = {{0}, false}; // Partial glyphs can be retrieved with ElementAt(...). // // A table consists of "nsGlyphCode"s which are viewed either as Unicode -// points (for nsUnicodeTable) or as direct glyph indices (for +// points (for nsPropertiesTable) or as direct glyph indices (for // nsOpenTypeTable) // ----------------------------------------------------------------------------- @@ -109,78 +109,68 @@ class nsGlyphTable { gfx::ShapedTextFlags mFlags; }; -// A Unicode construction is a set of all the stretchy MathML characters that -// can be rendered with Unicode using larger and/or partial glyphs. The entry -// of each stretchy character gives the 4 partial glyphs and the variants of -// bigger sizes (if any): -// Base | Top (or Left) | Middle | Bottom (or Right) | Glue | Size 0 | Size 1 +// An instance of nsPropertiesTable is associated with one primary font. Extra +// glyphs can be taken in other additional fonts when stretching certain +// characters. +// These supplementary fonts are referred to as "external" fonts to the table. + +// General format of MathFont Property Files from which glyph data are +// retrieved: +// ----------------------------------------------------------------------------- +// Each font should have its set of glyph data. For example, the glyph data for +// the "Symbol" font and the "MT Extra" font are in "mathfontSymbol.properties" +// and "mathfontMTExtra.properties", respectively. The mathfont property file +// is a set of all the stretchy MathML characters that can be rendered with that +// font using larger and/or partial glyphs. The entry of each stretchy character +// in the mathfont property file gives, in that order, the 4 partial glyphs: +// Top (or Left), Middle, Bottom (or Right), Glue; and the variants of bigger +// sizes (if any). // A position that is not relevant to a particular character is indicated there // with the UNICODE REPLACEMENT CHARACTER 0xFFFD. -// FIXME: This table was converted from the original mathfontUnicode.properties -// in bug 1007090. It has been unchanged for backward compatibility but probably -// at some point this should be standardized and implemented cross-browser. -// See also https://w3c.github.io/mathml-core/#unicode-based-glyph-assemblies -typedef char16_t const UnicodeConstruction[7]; -// clang-format off -static const UnicodeConstruction gUnicodeTableConstructions[] = { - { 0x0028, 0x239B, 0x0000, 0x239D, 0x239C, 0x0028, 0x0000 }, - { 0x0029, 0x239E, 0x0000, 0x23A0, 0x239F, 0x0029, 0x0000 }, - { 0x003D, 0x0000, 0x0000, 0x0000, 0x003D, 0x003D, 0x0000 }, - { 0x005B, 0x23A1, 0x0000, 0x23A3, 0x23A2, 0x005B, 0x0000 }, - { 0x005D, 0x23A4, 0x0000, 0x23A6, 0x23A5, 0x005D, 0x0000 }, - { 0x005F, 0x0000, 0x0000, 0x0000, 0x0332, 0x0332, 0x0000 }, - { 0x007B, 0x23A7, 0x23A8, 0x23A9, 0x23AA, 0x007B, 0x0000 }, - { 0x007C, 0x0000, 0x0000, 0x0000, 0x007C, 0x007C, 0x0000 }, - { 0x007D, 0x23AB, 0x23AC, 0x23AD, 0x23AA, 0x007D, 0x0000 }, - { 0x00AF, 0x0000, 0x0000, 0x0000, 0x0305, 0x00AF, 0x0000 }, - { 0x0332, 0x0000, 0x0000, 0x0000, 0x0332, 0x0332, 0x0000 }, - { 0x2016, 0x0000, 0x0000, 0x0000, 0x2016, 0x2016, 0x0000 }, - { 0x203E, 0x0000, 0x0000, 0x0000, 0x0305, 0x00AF, 0x0000 }, - { 0x2190, 0x2190, 0x0000, 0x0000, 0x23AF, 0x2190, 0x27F5 }, - { 0x2191, 0x2191, 0x0000, 0x0000, 0x23D0, 0x2191, 0x0000 }, - { 0x2192, 0x0000, 0x0000, 0x2192, 0x23AF, 0x2192, 0x27F6 }, - { 0x2193, 0x0000, 0x0000, 0x2193, 0x23D0, 0x2193, 0x0000 }, - { 0x2194, 0x2190, 0x0000, 0x2192, 0x23AF, 0x2194, 0x27F7 }, - { 0x2195, 0x2191, 0x0000, 0x2193, 0x23D0, 0x2195, 0x0000 }, - { 0x21A4, 0x2190, 0x0000, 0x22A3, 0x23AF, 0x21AA, 0x27FB }, - { 0x21A6, 0x22A2, 0x0000, 0x2192, 0x23AF, 0x21A6, 0x27FC }, - { 0x21BC, 0x21BC, 0x0000, 0x0000, 0x23AF, 0x21BC, 0x0000 }, - { 0x21BD, 0x21BD, 0x0000, 0x0000, 0x23AF, 0x21BD, 0x0000 }, - { 0x21C0, 0x0000, 0x0000, 0x21C0, 0x23AF, 0x21C0, 0x0000 }, - { 0x21C1, 0x0000, 0x0000, 0x21C1, 0x23AF, 0x21C1, 0x0000 }, - { 0x21D0, 0x0000, 0x0000, 0x0000, 0x0000, 0x21D0, 0x27F8 }, - { 0x21D2, 0x0000, 0x0000, 0x0000, 0x0000, 0x21D2, 0x27F9 }, - { 0x21D4, 0x0000, 0x0000, 0x0000, 0x0000, 0x21D4, 0x27FA }, - { 0x2223, 0x0000, 0x0000, 0x0000, 0x2223, 0x2223, 0x0000 }, - { 0x2225, 0x0000, 0x0000, 0x0000, 0x2225, 0x2225, 0x0000 }, - { 0x222B, 0x2320, 0x0000, 0x2321, 0x23AE, 0x222B, 0x0000 }, - { 0x2308, 0x23A1, 0x0000, 0x0000, 0x23A2, 0x2308, 0x0000 }, - { 0x2309, 0x23A4, 0x0000, 0x0000, 0x23A5, 0x2309, 0x0000 }, - { 0x230A, 0x0000, 0x0000, 0x23A3, 0x23A2, 0x230A, 0x0000 }, - { 0x230B, 0x0000, 0x0000, 0x23A6, 0x23A5, 0x230B, 0x0000 }, - { 0x23B0, 0x23A7, 0x0000, 0x23AD, 0x23AA, 0x23B0, 0x0000 }, - { 0x23B1, 0x23AB, 0x0000, 0x23A9, 0x23AA, 0x23B1, 0x0000 }, - { 0x27F5, 0x2190, 0x0000, 0x0000, 0x23AF, 0x27F5, 0x0000 }, - { 0x27F6, 0x0000, 0x0000, 0x2192, 0x23AF, 0x27F6, 0x0000 }, - { 0x27F7, 0x2190, 0x0000, 0x2192, 0x23AF, 0x27F7, 0x0000 }, - { 0x294E, 0x21BC, 0x0000, 0x21C0, 0x23AF, 0x294E, 0x0000 }, - { 0x2950, 0x21BD, 0x0000, 0x21C1, 0x23AF, 0x2950, 0x0000 }, - { 0x295A, 0x21BC, 0x0000, 0x22A3, 0x23AF, 0x295A, 0x0000 }, - { 0x295B, 0x22A2, 0x0000, 0x21C0, 0x23AF, 0x295B, 0x0000 }, - { 0x295E, 0x21BD, 0x0000, 0x22A3, 0x23AF, 0x295E, 0x0000 }, - { 0x295F, 0x22A2, 0x0000, 0x21C1, 0x23AF, 0x295F, 0x0000 }, -}; -// clang-format on +// ----------------------------------------------------------------------------- + +#define NS_TABLE_STATE_ERROR -1 +#define NS_TABLE_STATE_EMPTY 0 +#define NS_TABLE_STATE_READY 1 + +// helper to trim off comments from data in a MathFont Property File +static void Clean(nsString& aValue) { + // chop the trailing # comment portion if any ... + int32_t comment = aValue.RFindChar('#'); + if (comment > 0) { + aValue.Truncate(comment); + } + aValue.CompressWhitespace(); +} + +// helper to load a MathFont Property File +static nsresult LoadProperties(const nsACString& aName, + nsCOMPtr<nsIPersistentProperties>& aProperties) { + nsAutoCString uriStr; + uriStr.AssignLiteral("resource://gre/res/fonts/mathfont"); + uriStr.Append(aName); + uriStr.StripWhitespace(); // that may come from aName + uriStr.AppendLiteral(".properties"); + return NS_LoadPersistentPropertiesFromURISpec(getter_AddRefs(aProperties), + uriStr); +} -class nsUnicodeTable final : public nsGlyphTable { +class nsPropertiesTable final : public nsGlyphTable { public: - nsUnicodeTable() { MOZ_COUNT_CTOR(nsUnicodeTable); } + explicit nsPropertiesTable(const nsACString& aPrimaryFontName) + : mState(NS_TABLE_STATE_EMPTY) { + MOZ_COUNT_CTOR(nsPropertiesTable); + mGlyphCodeFonts.AppendElement(aPrimaryFontName); + } + + MOZ_COUNTED_DTOR(nsPropertiesTable) - MOZ_COUNTED_DTOR(nsUnicodeTable) + const nsCString& PrimaryFontName() const { return mGlyphCodeFonts[0]; } const nsCString& FontNameFor(const nsGlyphCode& aGlyphCode) const override { - MOZ_ASSERT_UNREACHABLE(); - return VoidCString(); + NS_ASSERTION(!aGlyphCode.IsGlyphID(), + "nsPropertiesTable can only access glyphs by code point"); + return mGlyphCodeFonts[aGlyphCode.font]; } virtual nsGlyphCode ElementAt(DrawTarget* aDrawTarget, @@ -218,60 +208,157 @@ class nsUnicodeTable final : public nsGlyphTable { gfxFontGroup* aFontGroup, const nsGlyphCode& aGlyph) override; private: - struct UnicodeConstructionComparator { - int operator()(const UnicodeConstruction& aValue) const { - if (mTarget < aValue[0]) { - return -1; - } - if (mTarget > aValue[0]) { - return 1; - } - return 0; - } - explicit UnicodeConstructionComparator(char16_t aTarget) - : mTarget(aTarget) {} - const char16_t mTarget; - }; - size_t mCachedIndex; + // mGlyphCodeFonts[0] is the primary font associated to this table. The + // others are possible "external" fonts for glyphs not in the primary font + // but which are needed to stretch certain characters in the table + nsTArray<nsCString> mGlyphCodeFonts; + + // Tri-state variable for error/empty/ready + int32_t mState; + + // The set of glyph data in this table, as provided by the MathFont Property + // File + nsCOMPtr<nsIPersistentProperties> mGlyphProperties; + + // mGlyphCache is a buffer containing the glyph data associated with + // mCharCache. + // For a property line 'key = value' in the MathFont Property File, + // mCharCache will retain the 'key' -- which is a Unicode point, while + // mGlyphCache will retain the 'value', which is a consecutive list of + // nsGlyphCodes, i.e., the pairs of 'code@font' needed by the char -- in + // which 'code@0' can be specified + // without the optional '@0'. However, to ease subsequent processing, + // mGlyphCache excludes the '@' symbol and explicitly inserts all optional '0' + // that indicates the primary font identifier. Specifically therefore, the + // k-th glyph is characterized by : + // 1) mGlyphCache[3*k],mGlyphCache[3*k+1] : its Unicode point + // 2) mGlyphCache[3*k+2] : the numeric identifier of the font where it comes + // from. + // A font identifier of '0' means the default primary font associated to this + // table. Other digits map to the "external" fonts that may have been + // specified in the MathFont Property File. + nsString mGlyphCache; }; /* virtual */ -nsGlyphCode nsUnicodeTable::ElementAt(DrawTarget* /* aDrawTarget */, - int32_t /* aAppUnitsPerDevPixel */, - gfxFontGroup* /* aFontGroup */, - char16_t aChar, bool /* aVertical */, - uint32_t aPosition) { +nsGlyphCode nsPropertiesTable::ElementAt(DrawTarget* /* aDrawTarget */, + int32_t /* aAppUnitsPerDevPixel */, + gfxFontGroup* /* aFontGroup */, + char16_t aChar, bool /* aVertical */, + uint32_t aPosition) { + if (mState == NS_TABLE_STATE_ERROR) { + return kNullGlyph; + } + // Load glyph properties if this is the first time we have been here + if (mState == NS_TABLE_STATE_EMPTY) { + nsresult rv = LoadProperties(PrimaryFontName(), mGlyphProperties); +#ifdef DEBUG + nsAutoCString uriStr; + uriStr.AssignLiteral("resource://gre/res/fonts/mathfont"); + uriStr.Append(PrimaryFontName()); + uriStr.StripWhitespace(); // that may come from mGlyphCodeFonts + uriStr.AppendLiteral(".properties"); + printf("Loading %s ... %s\n", uriStr.get(), + (NS_FAILED(rv)) ? "Failed" : "Done"); +#endif + if (NS_FAILED(rv)) { + mState = NS_TABLE_STATE_ERROR; // never waste time with this table again + return kNullGlyph; + } + mState = NS_TABLE_STATE_READY; + + // see if there are external fonts needed for certain chars in this table + nsAutoCString key; + nsAutoString value; + for (int32_t i = 1;; i++) { + key.AssignLiteral("external."); + key.AppendInt(i, 10); + rv = mGlyphProperties->GetStringProperty(key, value); + if (NS_FAILED(rv)) { + break; + } + Clean(value); + mGlyphCodeFonts.AppendElement(NS_ConvertUTF16toUTF8(value)); + } + } + // Update our cache if it is not associated to this character if (mCharCache != aChar) { - size_t match; - if (!BinarySearchIf(gUnicodeTableConstructions, 0, - std::size(gUnicodeTableConstructions), - UnicodeConstructionComparator(aChar), &match)) { + // The key in the property file is interpreted as ASCII and kept + // as such ... + char key[10]; + SprintfLiteral(key, "\\u%04X", aChar); + nsAutoString value; + nsresult rv = + mGlyphProperties->GetStringProperty(nsDependentCString(key), value); + if (NS_FAILED(rv)) { return kNullGlyph; } + Clean(value); + // See if this char uses external fonts; e.g., if the 2nd glyph is taken + // from the external font '1', the property line looks like + // \uNNNN = \uNNNN\uNNNN@1\uNNNN. + // This is where mGlyphCache is pre-processed to explicitly store all glyph + // codes as combined pairs of 'code@font', excluding the '@' separator. This + // means that mGlyphCache[3*k],mGlyphCache[3*k+1] will later be rendered + // with mGlyphCodeFonts[mGlyphCache[3*k+2]] + // Note: font identifier is internally an ASCII digit to avoid the null + // char issue + nsAutoString buffer; + int32_t length = value.Length(); + int32_t i = 0; // index in value + while (i < length) { + char16_t code = value[i]; + ++i; + buffer.Append(code); + // Read the next word if we have a non-BMP character. + if (i < length && NS_IS_HIGH_SURROGATE(code)) { + code = value[i]; + ++i; + } else { + code = char16_t('\0'); + } + buffer.Append(code); + + // See if an external font is needed for the code point. + // Limit of 9 external fonts + char16_t font = 0; + if (i + 1 < length && value[i] == char16_t('@') && + value[i + 1] >= char16_t('0') && value[i + 1] <= char16_t('9')) { + ++i; + font = value[i] - '0'; + ++i; + if (font >= mGlyphCodeFonts.Length()) { + NS_ERROR("Nonexistent font referenced in glyph table"); + return kNullGlyph; + } + } + buffer.Append(font); + } // update our cache with the new settings - mCachedIndex = match; + mGlyphCache.Assign(buffer); mCharCache = aChar; } - const UnicodeConstruction& construction = - gUnicodeTableConstructions[mCachedIndex]; - if (aPosition + 1 >= std::size(construction)) { + // 3* is to account for the code@font pairs + uint32_t index = 3 * aPosition; + if (index + 2 >= mGlyphCache.Length()) { return kNullGlyph; } nsGlyphCode ch; - ch.code = construction[aPosition + 1]; - ch.isGlyphID = false; - return ch.code == char16_t(0xFFFD) ? kNullGlyph : ch; + ch.code[0] = mGlyphCache.CharAt(index); + ch.code[1] = mGlyphCache.CharAt(index + 1); + ch.font = mGlyphCache.CharAt(index + 2); + return ch.code[0] == char16_t(0xFFFD) ? kNullGlyph : ch; } /* virtual */ -already_AddRefed<gfxTextRun> nsUnicodeTable::MakeTextRun( +already_AddRefed<gfxTextRun> nsPropertiesTable::MakeTextRun( DrawTarget* aDrawTarget, int32_t aAppUnitsPerDevPixel, gfxFontGroup* aFontGroup, const nsGlyphCode& aGlyph) { - NS_ASSERTION(!aGlyph.isGlyphID, - "nsUnicodeTable can only access glyphs by code point"); - return aFontGroup->MakeTextRun(&aGlyph.code, 1, aDrawTarget, + NS_ASSERTION(!aGlyph.IsGlyphID(), + "nsPropertiesTable can only access glyphs by code point"); + return aFontGroup->MakeTextRun(aGlyph.code, aGlyph.Length(), aDrawTarget, aAppUnitsPerDevPixel, mFlags, nsTextFrameUtils::Flags(), nullptr); } @@ -297,7 +384,7 @@ class nsOpenTypeTable final : public nsGlyphTable { bool aVertical) override; const nsCString& FontNameFor(const nsGlyphCode& aGlyphCode) const override { - NS_ASSERTION(aGlyphCode.isGlyphID, + NS_ASSERTION(aGlyphCode.IsGlyphID(), "nsOpenTypeTable can only access glyphs by id"); return mFontFamilyName; } @@ -375,7 +462,7 @@ nsGlyphCode nsOpenTypeTable::ElementAt(DrawTarget* aDrawTarget, } nsGlyphCode glyph; glyph.glyphID = glyphID; - glyph.isGlyphID = true; + glyph.font = -1; return glyph; } @@ -394,7 +481,7 @@ nsGlyphCode nsOpenTypeTable::BigOf(DrawTarget* aDrawTarget, nsGlyphCode glyph; glyph.glyphID = glyphID; - glyph.isGlyphID = true; + glyph.font = -1; return glyph; } @@ -417,7 +504,7 @@ bool nsOpenTypeTable::HasPartsOf(DrawTarget* aDrawTarget, already_AddRefed<gfxTextRun> nsOpenTypeTable::MakeTextRun( DrawTarget* aDrawTarget, int32_t aAppUnitsPerDevPixel, gfxFontGroup* aFontGroup, const nsGlyphCode& aGlyph) { - NS_ASSERTION(aGlyph.isGlyphID, + NS_ASSERTION(aGlyph.IsGlyphID(), "nsOpenTypeTable can only access glyphs by id"); gfxTextRunFactory::Parameters params = { @@ -450,15 +537,22 @@ class nsGlyphTableList final : public nsIObserver { NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER - nsUnicodeTable mUnicodeTable; + nsPropertiesTable mUnicodeTable; - nsGlyphTableList() {} + nsGlyphTableList() : mUnicodeTable("Unicode"_ns) {} nsresult Initialize(); nsresult Finalize(); private: ~nsGlyphTableList() = default; + + nsPropertiesTable* PropertiesTableAt(int32_t aIndex) { + return &mPropertiesTableList.ElementAt(aIndex); + } + int32_t PropertiesTableCount() { return mPropertiesTableList.Length(); } + // List of glyph tables; + nsTArray<nsPropertiesTable> mPropertiesTableList; }; NS_IMPL_ISUPPORTS(nsGlyphTableList, nsIObserver) @@ -736,13 +830,13 @@ bool nsMathMLChar::SetFontFamily(nsPresContext* aPresContext, nsFont& aFont, RefPtr<gfxFontGroup>* aFontGroup) { StyleFontFamilyList glyphCodeFont; - if (aGlyphCode.isGlyphID) { + if (aGlyphCode.font) { glyphCodeFont = StyleFontFamilyList::WithOneUnquotedFamily( aGlyphTable->FontNameFor(aGlyphCode)); } const StyleFontFamilyList& familyList = - aGlyphCode.isGlyphID ? glyphCodeFont : aDefaultFamilyList; + aGlyphCode.font ? glyphCodeFont : aDefaultFamilyList; if (!*aFontGroup || aFont.family.families != familyList) { nsFont font = aFont; @@ -845,7 +939,7 @@ class nsMathMLChar::StretchEnumContext { bool mTryParts; private: - bool mUnicodeTableTried = false; + AutoTArray<nsGlyphTable*, 16> mTablesTried; bool& mGlyphFound; }; @@ -882,7 +976,7 @@ bool nsMathMLChar::StretchEnumContext::TryVariants( NS_ASSERTION(isVertical, "Stretching should be in the vertical direction"); ch = aGlyphTable->BigOf(mDrawTarget, oneDevPixel, *aFontGroup, uchar, isVertical, 0); - if (ch.isGlyphID) { + if (ch.IsGlyphID()) { RefPtr<gfxFont> mathFont = aFontGroup->get()->GetFirstMathFont(); // For OpenType MATH fonts, we will rely on the DisplayOperatorMinHeight // to select the right size variant. @@ -911,7 +1005,7 @@ bool nsMathMLChar::StretchEnumContext::TryVariants( RefPtr<gfxTextRun> textRun = aGlyphTable->MakeTextRun(mDrawTarget, oneDevPixel, *aFontGroup, ch); nsBoundingMetrics bm = MeasureTextRun(mDrawTarget, textRun.get()); - if (ch.isGlyphID) { + if (ch.IsGlyphID()) { RefPtr<gfxFont> mathFont = aFontGroup->get()->GetFirstMathFont(); if (mathFont) { // MeasureTextRun should have set the advance width to the right @@ -1205,11 +1299,12 @@ bool nsMathMLChar::StretchEnumContext::EnumCallback( } if (!openTypeTable) { - // Make sure we only try the UnicodeTable once. - if (context->mUnicodeTableTried) { - return false; + if (context->mTablesTried.Contains(glyphTable)) { + return false; // already tried this one } - context->mUnicodeTableTried = true; + + // Only try this table once. + context->mTablesTried.AppendElement(glyphTable); } // If the unicode table is being used, then search all font families. If a diff --git a/layout/mathml/nsMathMLChar.h b/layout/mathml/nsMathMLChar.h @@ -47,20 +47,29 @@ enum { }; // A single glyph in our internal representation is either -// 1) a code pair from the mathfontFONTFAMILY.properties table, interpreted -// as a Unicode point. -// 2) a glyph index from the Open Type MATH table. +// 1) a 'code@font' pair from the mathfontFONTFAMILY.properties table. The +// 'code' is interpreted as a Unicode point. The 'font' is a numeric +// identifier given to the font to which the glyph belongs, which is 0 for the +// FONTFAMILY and > 0 for 'external' fonts. +// 2) a glyph index from the Open Type MATH table. In that case, all the glyphs +// come from the font containing that table and 'font' is just set to -1. struct nsGlyphCode { union { - char16_t code; + char16_t code[2]; uint32_t glyphID; }; - bool isGlyphID = true; + int8_t font; - bool Exists() const { return isGlyphID ? glyphID != 0 : code != 0; } + bool IsGlyphID() const { return font == -1; } + + int32_t Length() const { + return (IsGlyphID() || code[1] == char16_t('\0') ? 1 : 2); + } + bool Exists() const { return IsGlyphID() ? glyphID != 0 : code[0] != 0; } bool operator==(const nsGlyphCode& other) const { - return (other.isGlyphID == isGlyphID && - (isGlyphID ? other.glyphID == glyphID : other.code == code)); + return (other.font == font && ((IsGlyphID() && other.glyphID == glyphID) || + (!IsGlyphID() && other.code[0] == code[0] && + other.code[1] == code[1]))); } bool operator!=(const nsGlyphCode&) const = default; };