Closed Bug 77146 Opened 23 years ago Closed 23 years ago

[patch] crash when navigating mathml pages

Categories

(Core :: MathML, defect, P1)

defect

Tracking

()

RESOLVED FIXED
mozilla0.9

People

(Reporter: rbs, Assigned: rbs)

References

()

Details

(Keywords: crash, Whiteboard: have patch, have r=dbaron, waiting sr/a)

Attachments

(3 files)

Currently, in order to check the existence of fonts, the stretchy code caches a 
weak pointer on the presentation context in the glyph tables. Each table is 
initialized once and never changes because it maps to an underlying font that 
isn't supposed to change. However the presentation context can be renewed when
navigating mathml pages (or when printing), so that the cached reference becomes
a dead object, and attempts to use this object cause a crash. How did this bug
stay unnoticed for so long, I don't know. 

Here is a stack trace of a crash. It shows that the 'nsIPresContext*' used in 
CheckFontExistence() is different from the others 'nsIPresContext*' with which 
the document is being rendered:

CheckFontExistence(nsIPresContext * 0x04b86ee0, nsString & {...}) line 124 + 42 
bytes
nsGlyphTable::ElementAt(nsMathMLChar * 0x02d100d8, unsigned int 5) line 356 + 22 
bytes
nsGlyphTable::BigOf(nsMathMLChar * 0x02d100d8, int 1) line 244 + 23 bytes
nsGlyphTable::HasVariantsOf(nsMathMLChar * 0x02d100d8) line 500 + 18 bytes
nsGlyphTable::Has(nsMathMLChar * 0x02d100d8) line 483 + 12 bytes
nsGlyphTableList::GetGlyphTableFor(nsMathMLChar * 0x02d100d8) line 776 + 12 
bytes
nsMathMLChar::SetData(nsIPresContext * 0x04b86520, nsString & {...}) line 1085 + 
15 bytes
nsMathMLmoFrame::Init(nsMathMLmoFrame * const 0x02d1005c, nsIPresContext * 
0x04b86520, nsIContent * 0x0433d240, nsIFrame * 0x02d0fd7c, nsIStyleContext * 
0x04d1b840, nsIFrame * 0x00000000) line 184
nsCSSFrameConstructor::InitAndRestoreFrame(nsIPresContext * 0x04b86520, 
nsFrameConstructorState & {...}, nsIContent * 0x0433d240, nsIFrame * 0x02d0fd7c, 
nsIStyleContext * 0x04d1b840, nsIFrame * 0x00000000, nsIFrame * 0x02d1005c) line 
6728 + 32 bytes
nsCSSFrameConstructor::ConstructMathMLFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433d240, nsIFrame * 0x02d0fd7c, nsIAtom * 0x02728840, int 7, nsIStyleContext 
* 0x04d1b840, nsFrameItems & {...}) line 6968
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433d240, nsIFrame * 0x02d0fd7c, nsIAtom * 0x02728840, int 7, nsIStyleContext 
* 0x04d1b840, nsFrameItems & {...}, int 0) line 7268 + 52 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0433d240, nsIFrame 
* 0x02d0fd7c, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessChildren(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0433dbb0, nsIFrame 
* 0x02d0fd7c, int 1, nsFrameItems & {...}, int 0, nsTableCreator * 0x00000000) 
line 11292 + 43 bytes
nsCSSFrameConstructor::ConstructMathMLFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433dbb0, nsIFrame * 0x02d0fd30, nsIAtom * 0x027272b0, int 7, nsIStyleContext 
* 0x04d191a0, nsFrameItems & {...}) line 6977 + 38 bytes
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433dbb0, nsIFrame * 0x02d0fd30, nsIAtom * 0x027272b0, int 7, nsIStyleContext 
* 0x04d191a0, nsFrameItems & {...}, int 0) line 7268 + 52 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0433dbb0, nsIFrame 
* 0x02d0fd30, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessBlockChildren(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433a290, nsIFrame * 0x02d0fd30, int 1, nsFrameItems & {...}, int 1) line 
12450 + 37 bytes
nsCSSFrameConstructor::ConstructBlock(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, const nsStyleDisplay * 
0x04d19c14, nsIContent * 0x0433a290, nsIFrame * 0x02d0f8cc, nsIStyleContext * 
0x04d19e10, nsIFrame * 0x02d0fd30) line 12399 + 36 bytes
nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, const 
nsStyleDisplay * 0x04d19c14, nsIContent * 0x0433a290, nsIFrame * 0x02d0f8cc, 
nsIStyleContext * 0x04d19e10, nsFrameItems & {...}) line 6502 + 43 bytes
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0433a290, nsIFrame * 0x02d0f8cc, nsIAtom * 0x0145f030, int 3, nsIStyleContext 
* 0x04d19e10, nsFrameItems & {...}, int 0) line 7289 + 48 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0433a290, nsIFrame 
* 0x02d0f8cc, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessBlockChildren(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x042fb0a0, nsIFrame * 0x02d0f8cc, int 1, nsFrameItems & {...}, int 1) line 
12450 + 37 bytes
nsCSSFrameConstructor::ConstructBlock(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, const nsStyleDisplay * 
0x04d18d14, nsIContent * 0x042fb0a0, nsIFrame * 0x02d0f564, nsIStyleContext * 
0x04d18f10, nsIFrame * 0x02d0f8cc) line 12399 + 36 bytes
nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, const 
nsStyleDisplay * 0x04d18d14, nsIContent * 0x042fb0a0, nsIFrame * 0x02d0f564, 
nsIStyleContext * 0x04d18f10, nsFrameItems & {...}) line 6502 + 43 bytes
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x042fb0a0, nsIFrame * 0x02d0f564, nsIAtom * 0x0145c650, int 3, nsIStyleContext 
* 0x04d18f10, nsFrameItems & {...}, int 0) line 7289 + 48 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x042fb0a0, nsIFrame 
* 0x02d0f564, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessChildren(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x042fbad0, nsIFrame 
* 0x02d0f564, int 1, nsFrameItems & {...}, int 1, nsTableCreator * 0x00000000) 
line 11292 + 43 bytes
nsCSSFrameConstructor::ConstructTableCellFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x042fbad0, nsIFrame * 0x02d0daf4, nsIStyleContext * 0x04d14ee0, nsTableCreator 
& {...}, int 0, nsFrameItems & {...}, nsIFrame * & 0x02d0f508, nsIFrame * & 
0x02d0f564, int & 0) line 2950 + 40 bytes
nsCSSFrameConstructor::TableProcessChild(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent & 
{...}, nsIFrame * 0x02d0daf4, nsIAtom * 0x01465d90, nsIStyleContext * 
0x04d119f0, nsTableCreator & {...}, nsFrameItems & {...}, nsIFrame * & 
0x00000000) line 3214 + 59 bytes
nsCSSFrameConstructor::TableProcessChildren(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x04330400, nsIFrame * 0x02d0daf4, nsTableCreator & {...}, nsFrameItems & {...}, 
nsIFrame * & 0x00000000) line 3125 + 69 bytes
nsCSSFrameConstructor::ConstructTableRowFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x04330400, nsIFrame * 0x02d0da50, nsIStyleContext * 0x04d119f0, nsTableCreator 
& {...}, int 0, nsFrameItems & {...}, nsIFrame * & 0x02d0daf4, int & 1) line 
2821 + 42 bytes
nsCSSFrameConstructor::TableProcessChild(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent & 
{...}, nsIFrame * 0x02d0da50, nsIAtom * 0x01465f70, nsIStyleContext * 
0x04d104b0, nsTableCreator & {...}, nsFrameItems & {...}, nsIFrame * & 
0x00000000) line 3200 + 55 bytes
nsCSSFrameConstructor::TableProcessChildren(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x04330850, nsIFrame * 0x02d0da50, nsTableCreator & {...}, nsFrameItems & {...}, 
nsIFrame * & 0x00000000) line 3125 + 69 bytes
nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x04330850, nsIFrame * 0x02c9a970, nsIStyleContext * 0x04d104b0, nsTableCreator 
& {...}, int 0, nsFrameItems & {...}, nsIFrame * & 0x02d0da04, nsIFrame * & 
0x02d0da50, int & 0) line 2593 + 42 bytes
nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, const 
nsStyleDisplay * 0x04d102b4, nsIContent * 0x04330850, nsIFrame * 0x02c9a970, 
nsIStyleContext * 0x04d104b0, nsFrameItems & {...}) line 6550 + 63 bytes
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x04330850, nsIFrame * 0x02c9a970, nsIAtom * 0x01461be0, int 3, nsIStyleContext 
* 0x04d104b0, nsFrameItems & {...}, int 0) line 7289 + 48 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x04330850, nsIFrame 
* 0x02c9a970, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessBlockChildren(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0432e530, nsIFrame * 0x02c9a970, int 1, nsFrameItems & {...}, int 1) line 
12450 + 37 bytes
nsCSSFrameConstructor::ConstructBlock(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, const nsStyleDisplay * 
0x04d01d14, nsIContent * 0x0432e530, nsIFrame * 0x02c9a8ac, nsIStyleContext * 
0x04d01f10, nsIFrame * 0x02c9a970) line 12399 + 36 bytes
nsCSSFrameConstructor::ConstructFrameByDisplayType(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, const 
nsStyleDisplay * 0x04d01d14, nsIContent * 0x0432e530, nsIFrame * 0x02c9a8ac, 
nsIStyleContext * 0x04d01f10, nsFrameItems & {...}) line 6502 + 43 bytes
nsCSSFrameConstructor::ConstructFrameInternal(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0432e530, nsIFrame * 0x02c9a8ac, nsIAtom * 0x0145bf00, int 3, nsIStyleContext 
* 0x04d01f10, nsFrameItems & {...}, int 0) line 7289 + 48 bytes
nsCSSFrameConstructor::ConstructFrame(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0432e530, nsIFrame 
* 0x02c9a8ac, nsFrameItems & {...}) line 7156 + 56 bytes
nsCSSFrameConstructor::ProcessChildren(nsIPresShell * 0x04cba420, nsIPresContext 
* 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 0x0432d220, nsIFrame 
* 0x02c9a8ac, int 1, nsFrameItems & {...}, int 1, nsTableCreator * 0x00000000) 
line 11292 + 43 bytes
nsCSSFrameConstructor::ConstructDocElementFrame(nsIPresShell * 0x04cba420, 
nsIPresContext * 0x04b86520, nsFrameConstructorState & {...}, nsIContent * 
0x0432d220, nsIFrame * 0x02d049bc, nsIStyleContext * 0x04cd6910, nsIFrame * & 
0x02c9a8ac) line 3540
nsCSSFrameConstructor::ContentInserted(nsCSSFrameConstructor * const 0x04cba7b0, 
nsIPresContext * 0x04b86520, nsIContent * 0x00000000, nsIContent * 0x0432d220, 
int 0, nsILayoutHistoryState * 0x00000000) line 8471
StyleSetImpl::ContentInserted(StyleSetImpl * const 0x04cba8e0, nsIPresContext * 
0x04b86520, nsIContent * 0x00000000, nsIContent * 0x0432d220, int 0) line 1250
PresShell::InitialReflow(PresShell * const 0x04cba420, int 12645, int 9000) line 
2502
nsXMLContentSink::StartLayout() line 1563
nsXMLContentSink::DidBuildModel(nsXMLContentSink * const 0x04cebbc0, int 1) line 
288
CWellFormedDTD::DidBuildModel(CWellFormedDTD * const 0x04cb81f0, unsigned int 0, 
int 1, nsIParser * 0x04ced820, nsIContentSink * 0x04cebbc0) line 294 + 20 bytes
nsParser::DidBuildModel(unsigned int 0) line 1427 + 60 bytes
nsParser::ResumeParse(int 1, int 1) line 1910
nsParser::ContinueParsing() line 1528 + 17 bytes
CSSLoaderImpl::Cleanup(URLKey & {...}, SheetLoadData * 0x04301920) line 709
CSSLoaderImpl::SheetComplete(nsICSSStyleSheet * 0x00000000, SheetLoadData * 
0x04301920) line 833
CSSLoaderImpl::ParseSheet(nsIUnicharInputStream * 0x0430d660, SheetLoadData * 
0x04301920, int & 1, nsICSSStyleSheet * & 0x04308580) line 868
CSSLoaderImpl::DidLoadStyle(nsIStreamLoader * 0x04301600, nsString * 0x0430af20, 
SheetLoadData * 0x04301920, unsigned int 0) line 903 + 27 bytes
SheetLoadData::OnStreamComplete(SheetLoadData * const 0x04301920, 
nsIStreamLoader * 0x04301600, nsISupports * 0x00000000, unsigned int 0, unsigned 
int 494, const char * 0x04308c20) line 643
nsStreamLoader::OnStopRequest(nsStreamLoader * const 0x04301604, nsIRequest * 
0x043014d0, nsISupports * 0x00000000, unsigned int 0) line 120 + 81 bytes
nsHTTPFinalListener::OnStopRequest(nsHTTPFinalListener * const 0x04301220, 
nsIRequest * 0x043014d0, nsISupports * 0x00000000, unsigned int 0) line 1137 + 
38 bytes
nsHTTPChannel::ResponseCompleted(nsIStreamListener * 0x04301220, unsigned int 0) 
line 2348 + 32 bytes
nsHTTPCacheListener::OnStopRequest(nsHTTPCacheListener * const 0x04308950, 
nsIRequest * 0x0430c4f4, nsISupports * 0x00000000, unsigned int 0) line 169
nsOnStopRequestEvent::HandleEvent() line 159
nsARequestObserverEvent::HandlePLEvent(PLEvent * 0x043080f4) line 64
PL_HandleEvent(PLEvent * 0x043080f4) line 588 + 10 bytes
PL_ProcessPendingEvents(PLEventQueue * 0x0053ec90) line 518 + 9 bytes
_md_EventReceiverProc(HWND__ * 0x002106c8, unsigned int 49381, unsigned int 0, 
long 5500048) line 1069 + 9 bytes
USER32! 77e148dc()
USER32! 77e14aa7()
USER32! 77e266fd()
nsAppShellService::Run(nsAppShellService * const 0x00561e20) line 408
main1(int 1, char * * 0x00484470, nsISupports * 0x00000000) line 1005 + 32 bytes
main(int 1, char * * 0x00484470) line 1300 + 37 bytes
mainCRTStartup() line 338 + 17 bytes
KERNEL32! 77e992a6()

The easier
Will attach a fix that avoids caching the presentation context -- just pass
it as a param where appropriate...
Status: NEW → ASSIGNED
Keywords: crash
Priority: -- → P1
Whiteboard: 0.9
Target Milestone: --- → mozilla0.9
I attached a patch that will protect from holding a reference to a pres context
that is gone. The glyph tables retain the metadata about the stretchy characters 
into physical fonts that are not subject to change. If the pres context change,
the crash will not happen any more. Awaiting r/sr/a for m0.9. Thanks...
Note: this is a lazy code in which a glyph table is created if a page with 
mathml markup is encountered, and if a stretchy char is needed from the table.
When mathml is enabled, a user that never hits a mathml-authored page is freed
from its impact (currently, only the mathml atoms and stylesheet are loaded 
upfront in mathml-enabled builds, BTW).
Summary: crash when navigating mathml pages → [patch] crash when navigating mathml pages
Whiteboard: 0.9 → have patch, waiting r/sr/a
Adding 0.9 helpers.

/be
Could you summarize the changes in the patch other than the ones having to do
with caching the presentation context (or that don't immediately appear directly
related)?
[A very brief outline. The inner workings are a bit involved as I described at
http://www.mozilla.org/projects/mathml/fonts/encoding/. This only describes the
initial font selection. The process by which stretching happens is not covered.]

A nsGlyphTable maps to a single font, i.e., it contains the metadata about the
stretchy characters that can be rendered with glyphs in that font. Just like a
letter 'a' can be found in several fonts, a stretchy character can exists in
several fonts. Stretching is possible with a particular character only if there
exists at least one installed font for which the nsGlyphTable contains the
character. But certain characters require to mix glyphs from multiple fonts at
once. Hence these particular characters can only be stretched if all of the
multiple fonts are installed. Hence, of two strecthy characters in the same
table, one character could stretch, while the other wouldn't if it requires
another font that is missing.

The fundamental function that tells if a glyph is there is
nsGlyphTable::ElementAt(). So this functions needs a way to check the validity
of fonts. 

In the old code, nsGlyphTable was simply caching a mPresContext member
at initiliazation. Since this causes the crash, the patch is now making
it a parameter. The trick is to ensure that all the code paths that will
ultimately hit nsGlyphTable::ElementAt() have the pres context.

nsGlyphTableList contains an ordered list of candidate tables, i.e., those fonts
for which the metadata (a.k.a, MathFont Property Files) have actually been built
and installed in Mozilla. From this list, sublists can be extracted depending on 
the particular character at hand, and/or the CSS font-family property. That's
what the GetPreferredListAt() and GetdListFor() are doing. They need to weed out
author' specified fonts that are not installed on a particular user' system so
that they can provide fallback alternative fonts that are installed if
necessary. They use the pres context for this purpose.
 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) {
+    if (!CheckFontExistence(aPresContext, *mFontName[0])) {
+      mState = NS_TABLE_STATE_ERROR; // never waste time with this table again
+      return kNullGlyph;
+    }

What will happen if you change from presContext A to presContext B (say,
one for printing) and then back to A again, and B is missing a font that
A has?  Won't this cause you to lose the ability to display the
characters in that font?


+  PRInt32
+  GetPreferredListAt(nsIPresContext* aPresContext,
+                     PRInt32         aStartingIndex,
+                     nsVoidArray*    aGlyphTableList);

By changing this not to return nsresult you lose the ability to
propagate return values.  Do you really want to do this?  It would
probably be better to stick a PRInt32* as the last param.


+  PRBool alreadyCSS = PR_FALSE;

What's this?  CSS has a meaning to me, and I don't think it's what this
is referring to.


I don't really understand the changes to PreferredFontEnumCallback and
or nsMathMLChar::Stretch, but that's OK.
Attached file Updated patch
I attached and updated patch to incorporate dbaron suggestions:
1) removed the undue CheckFontExistence() which would have erroneously disabled 
a table.
2) added a param to GetPreferredListAt().
=====

>+  PRBool alreadyCSS = PR_FALSE;
>
>What's this?  CSS has a meaning to me, and I don't think it's what this
>is referring to.

There are two ways to specify the preferred fonts with which to stretch a 
character:
1) Authors can use the CSS font-family fist property
2) Users can specify preferred lists in their matfont.properties file for each 
character.

If the user has specified something, it takes precedence over what the
author's list. If the user hasn't specified anything (or if what was specified
doesn't exit -- BTW, that's what the aCount param tells), then the author's list 
is used, and this causes to alreadyCSS flag to be set (i.e., the current list 
comes from CSS).

Later on, if the first strategy of stretching fails, and the stretching code 
has to try another strategy, the flag helps to possibly skip the step of 
enumerating the CSS font-family list again.

>I don't really understand the changes to PreferredFontEnumCallback and
>or nsMathMLChar::Stretch, but that's OK.

The PreferredFontEnumCallback is the hook to enumerate the user's preferred
fonts for a particular character. The StretchyFontEnumCallback is the hook to 
enumerate the document-wide author's CSS font-family list.
Whiteboard: have patch, waiting r/sr/a → have patch, have r=dbaron, waiting sr/a
sr=waterson
I think this should go into 0.9's branch, and so do other drivers.  rbs, can you
check it in?  Thanks,

/be
Great, I will land on the trunk and follow suit on the branch...
Landed in the trunk and the m0.9 branch. Resolving as FIXED.
Status: ASSIGNED → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: