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:
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 # ⏝ (MathML 2.0)
operator.\uFE37.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # ⏞ (MathML 2.0)
operator.\uFE38.postfix = lspace:0 rspace:0 stretchy accent direction:horizontal # ⏟ (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;
};