Closed
Bug 102706
Opened 25 years ago
Closed 25 years ago
change nsFontMetricsWin.cpp to use nsCompressedCharMap
Categories
(Core :: Internationalization, defect, P2)
Tracking
()
RESOLVED
FIXED
mozilla0.9.6
People
(Reporter: ftang, Assigned: shanjian)
References
Details
(Keywords: intl)
Attachments
(1 file, 11 obsolete files)
|
59.83 KB,
patch
|
rbs
:
review+
attinasi
:
superreview+
|
Details | Diff | Splinter Review |
we should update nsFontMetricsWin.cpp to use nsCompressedCharMap to
1. save space
2. prepare for Surrogate support
| Reporter | ||
Comment 1•25 years ago
|
||
here is the information bstell provide:
Change the map from PRUint32* to PRUint16*
old: PRUint32* mMap;
new: PRUint16* mCCMap;
Change the alloc/set-chars call:
old: aSelf->mMap = (PRUint32*) PR_Calloc(2048, 4);
old: res = mapper->FillInfo(aSelf->mMap);
old: if (NS_SUCCEEDED(res)) {
new: aSelf->mCCMap = MapperToCCMap(mapper);
new: if (aSelf->mCCMap)
Change the char test macro:
old: if (FONT_HAS_GLYPH(font->mMap, aChar)) {
new: if (CCMAP_HAS_CHAR(font->mCCMap, aChar)) {
Change the map free call:
old: PR_FREEIF(charsetMap->mInfo->mMap);
new: FreeCCMap(charsetMap->mInfo->mCCMap);
| Reporter | ||
Comment 2•25 years ago
|
||
shanjian, can you work with bstell to do this ?
Assignee: ftang → shanjian
| Assignee | ||
Comment 4•25 years ago
|
||
After I looked into nsFontMetricsWin, I found the change is far more complicated than I expected. I need to allocate myself enough time to do this.
| Reporter | ||
Comment 5•25 years ago
|
||
we are still not sure how this support interace with 102557 yet. But we
definitly don't want to create 17 x 8K bytes for each font. We probably need to
implement this on window first before we add surrogate font support at 102557.
>After I looked into nsFontMetricsWin, I found the change is far more
>complicated than I expected. I need to allocate myself enough time to do this.
Not trival
Blocks: 102557
| Assignee | ||
Comment 7•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Target Milestone: --- → mozilla0.9.6
| Assignee | ||
Updated•25 years ago
|
Attachment #52843 -
Attachment is obsolete: true
| Assignee | ||
Comment 8•25 years ago
|
||
| Assignee | ||
Comment 9•25 years ago
|
||
| Assignee | ||
Comment 10•25 years ago
|
||
bstell, can you code view my patch, especially the part in
nsCompressedCharMap.cpp?
rbs, can you code review my patch for the windows part?
| Assignee | ||
Comment 11•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Attachment #53116 -
Attachment is obsolete: true
| Assignee | ||
Updated•25 years ago
|
Attachment #53149 -
Attachment is obsolete: true
| Assignee | ||
Comment 12•25 years ago
|
||
Comment 13•25 years ago
|
||
+ .\$(OBJDIR)\nsCCMapWrap.obj \
>>>you can get rid of this strange '#include "..\nsCompressedCharMap.cpp"'
by adding nsCompressedCharMap to gfx/src/makefile.win
============
+ nsCRT::memset(map, 0, sizeof(PRUint32)*UCS2_MAP_LEN);
>>>nit:
+ nsCRT::memset(map, 0, sizeof(map));
============
+ ccmap = MapToCCMap(map);
+ return ccmap;
>>>nit:
+ return MapToCCMap(map);
============
+ PRUint16* ccmap = GetFontCCMAP(aDC, aShortName, aFontType, aCharset);
+ if (ccmap == nsnull) {
>>>nit:
+ if (!ccmap)
============
font = LoadSubstituteFont(aDC, &name);
if (font) {
- ADD_GLYPH(font->mMap, c);
mSubstituteFont = font;
return font;
}
>>>it is incorrect to remove that, it is the very first char that causes
the creation of the substitution font, and it needs to be recorded that it is
representable in the substitution font that was just created.
=====
- nsFontWin* font = new nsFontWinSubstitute(&logFont, hfont, map,
displayUnicode);
+ nsFontWinSubstitute* font = new nsFontWinSubstitute(&logFont, hfont,
nsnull, displayUnicode);
>>>see my comments about the constructor below
==============
if (mSubstituteFont) {
- nsFontWinA* substituteFont = (nsFontWinA*)mSubstituteFont;
- ADD_GLYPH(substituteFont->mMap, aChar);
- ADD_GLYPH(substituteFont->mSubsets[0]->mMap, aChar);
return mSubstituteFont;
}
>>>need to set that the char is representable to keep fontHasGlyph() in sync
==============
if (substituteSubset->Load(aDC, this, substituteFont)) {
- ADD_GLYPH(substituteFont->mMap, aChar);
- ADD_GLYPH(substituteFont->mSubsets[0]->mMap, aChar);
mSubstituteFont = (nsFontWin*)substituteFont;
return mSubstituteFont;
}
>>>ditto here
==========================
@@ -4418,27 +4313,13 @@
HFONT hfont = aFontMetricsWinA->CreateFontHandle(aDC, logFont);
if (hfont) {
int i = gCharsetToIndex[mCharset];
- PRUint32* charsetMap = gCharsetInfo[i].mMap;
- if (!charsetMap) {
- charsetMap = (PRUint32*) PR_Calloc(2048, 4); // deleted in FreeGlobals()
- if (charsetMap) {
- gCharsetInfo[i].mMap = charsetMap;
- gCharsetInfo[i].GenerateMap(&gCharsetInfo[i]);
- }
- else {
- ::DeleteObject(hfont);
- return 0;
- }
- }
- mMap = (PRUint32*) PR_Calloc(2048, 4); // deleted in ~nsFontSubset()
- if (!mMap) {
+ if (!gCharsetInfo[i].mCCMap)
+ gCharsetInfo[i].mCCMap = gCharsetInfo[i].GenerateMap(&gCharsetInfo[i]);
+ if (!gCharsetInfo[i].mCCMap) {
::DeleteObject(hfont);
return 0;
}
- PRUint32* fontMap = aFont->mMap;
- for (int j = 0; j < 2048; ++j) {
- mMap[j] = (charsetMap[j] & fontMap[j]);
- }
+ mCCMap = gCharsetInfo[i].mCCMap;
mCodePage = gCharsetInfo[i].mCodePage;
mFont = hfont;
>>> you are changing the semantics here. The previous code didn't assume that
all the glyphs for a charset were available. But I think the change is ok. In
case of problems we will see the empty squares and can revisit the change.
======
+// A "substitute font" to deal with missing glyphs -- see bug 6585
+// Ultimately, this "font" should map Unicodes to other character codes
+// for which we *do* have glyphs on the system.
+// But, for now, this "font" is only mapping all characters to
+// a REPLACEMENT CHAR. If the member variable mDisplayUnicode set,
+// the font will instead render unicode points of missing glyphs in
+// the format: &xNNNN;
>>> these comments seem outdated now that there is transliteration + fallback
to the REPLACEMENT CHAR + hex representation
============
+ nsFontWinSubstitute[A](LOGFONT* aLogFont, HFONT aFont, PRUint16* aCCMap,
PRBool aDisplayUnicode);
>>>you can get rid of |PRUint16* aCCMap| since it is always null
============
+ virtual inline PRBool HasGlyph(PRUnichar ch) {return
IS_REPRESENTABLE(mRepresentableCharMap, ch);};
+ virtual inline void SetRepresentable(PRUnichar ch)
{SET_REPRESENTABLE(mRepresentableCharMap, ch);};
>>>no need to add 'inline' since the method is already inline by virtue of the
fact its body is in the class declaration.
I suggest to get rid of |CCMAP_HAS_CHAR(font->mCCMap, aChar)| and to consistenly
use |font->HasGlyph(aChar)| everywhere.
| Assignee | ||
Comment 14•25 years ago
|
||
| Assignee | ||
Comment 15•25 years ago
|
||
rbs, thanks a lot for your careful code reviewing. You caught many good points.
There are several issue I want to discuss with you or clarify.
. How to include "nsCompressedCharMap.cpp" in makefile.win. I can't find a way
to do it. Can you show me how?
. Yes, I did change the semantic for nsFontMetricsWinA and its subset.
Originally subset->charmap = fontA->map & subset->charset->map. When it comes to
selecting subset, we already know the fond has such a glyph, so only charset map
need to be checked. That saved some operation. (And solve the problem that ccmap
can't be operated directly.)
| Assignee | ||
Updated•25 years ago
|
Attachment #53191 -
Attachment is obsolete: true
Comment 16•25 years ago
|
||
if (mSubstituteFont) {
- if (!FONT_HAS_GLYPH(currFont->mMap, *currChar)) {
+ if (!(currFont->HasGlyph(*currChar))) {
>>>nit: excessive parentheses
=========
- nsFontWinA* substituteFont = (nsFontWinA*)mSubstituteFont;
- ADD_GLYPH(substituteFont->mMap, aChar);
- ADD_GLYPH(substituteFont->mSubsets[0]->mMap, aChar);
+ //make the char representable so that we don't have to go over all font
before fallback to
+ //subsituteFont.
+ ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(aChar);
return mSubstituteFont;
}
>>>>this still wouldn't work as expected. substituteFont->mSubsets[0] also needs
to be updated. The way to go about this is, like you did in nsFontWinSubstitute,
tweak the |class nsFontSubsetSubstitute| to add a normal map[2048] there, and
then overload fontHasGlyph() there, then change the tests for subset->mMap to
subset->HasGlyph() everywhere.
======
re: mekefile.win
not sure what is the build problem that you are getting here, but it is the same
setup as nsFont.h/.cpp (maybe class declarations need NS_COM or something). One
of the build folks may help here.
| Reporter | ||
Comment 17•25 years ago
|
||
*** Bug 98637 has been marked as a duplicate of this bug. ***
| Assignee | ||
Comment 18•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Attachment #53287 -
Attachment is obsolete: true
Comment 19•25 years ago
|
||
Getting there, but a few things are still missing.
=========
if (mSubstituteFont) {
- nsFontWinA* substituteFont = (nsFontWinA*)mSubstituteFont;
- ADD_GLYPH(substituteFont->mMap, aChar);
- ADD_GLYPH(substituteFont->mSubsets[0]->mMap, aChar);
+ //make the char representable so that we don't have to go over all font
before fallback to
+ //subsituteFont.
+ ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(aChar);
return mSubstituteFont;
}
[...]
if (substituteSubset->Load(aDC, this, substituteFont)) {
- ADD_GLYPH(substituteFont->mMap, aChar);
- ADD_GLYPH(substituteFont->mSubsets[0]->mMap, aChar);
+ substituteFont->SetRepresentable(aChar);
mSubstituteFont = (nsFontWin*)substituteFont;
return mSubstituteFont;
}
>>>see my previous comments. Look for the class |nsFontSubstituteSubset|
and also add what is needed there. Then, you could do:
+ substituteFont->SetRepresentable(aChar);
+ substituteFont->mSubsets[0]->SetRepresentable(aChar);
The _two_ settings are needed for a transparent integration of the 'A' functions
higher up.
===========
for (; j < i-1; ++j) {
// NOTE: we are overwriting variables here (we now *know* that
we
// will break out of the bigger outer loop after the
callback...)
prevFont = (nsFontWinA*)mLoadedFonts[j];
- if (FONT_HAS_GLYPH(prevFont->mMap, *currChar)) {
- subset = prevFont->mSubsets;
- endSubsets = subset + prevFont->mSubsetsCount;
- while (subset < endSubsets) {
- if (!(*subset)->mMap) {
- if (!(*subset)->Load(aDC, this, prevFont)) {
- ++subset;
- continue;
- }
- }
- if (FONT_HAS_GLYPH((*subset)->mMap, *currChar)) {
- // Another font was found, we cannot use the
- // current font for this char
- goto callback;
- }
- ++subset;
- }
+ if (prevFont->HasGlyph(*currChar)) {
+ //as long as we know prevFont cover this char, there is
really no need to
+ //find which subset here
+ goto callback;
}
}
>>>This assumes that prevFont also has a subset with the char. However, as the
topcrash in bug 103777 showed, this assumption is not always valid. Even when
some fonts claim to have a glyph, it could happen that the subset of interest
hasn't been constructed because GenerateMap() doesn't cover all the possible
charsets. Might be best to revert to correctness here since the savings are not
really significant (this particular code only gets called in the Win95-Ja
situation).
=======
The makefile.win hack is a must-fix especially given that gtk doesn't have
the hack. (BTW, do well to elaborate on the errors that you get when you hook
nsCompressedCharMap.cpp to "gfx/src/makefile.win" in the same way as nsFont.cpp)
| Assignee | ||
Comment 20•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Attachment #53436 -
Attachment is obsolete: true
| Assignee | ||
Comment 21•25 years ago
|
||
rbs, I update my patch to accomodate your recent change in nsFontMetricsWin.cpp.
Could you check one more time? thanks.
Comment 22•25 years ago
|
||
I am still seeing loose ends in the handling of the font substitute in the 'A'
case. C.f. to my comments above.
nsFontWinA::ResolveForwards() will break with the current patch. Indeed, suppose
that a mLoadedFonts[i] happens to be a nsFontWinSubstituteA, then the code will
attempt to find the subset of interest for a currchar that was substituted, that
will fail because the substitute subset hasn't be properly setup and kept in
sync.
Also, the makefile.win hack (with the strange wrap of '#include
"..\nsCompressedCharMap.cpp"') is still lurking there.
| Assignee | ||
Comment 23•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Attachment #53117 -
Attachment is obsolete: true
| Assignee | ||
Updated•25 years ago
|
Attachment #53756 -
Attachment is obsolete: true
| Assignee | ||
Comment 24•25 years ago
|
||
rbs,
For your first concern, it needs some explaination. In my new code,
charmap of subset is no longer updatable. In original code,
subset->charmap = font->charmap & (charmap of charset)
Since in most situation, before we get down to subset, we already
know that font->charmap contains that char. nsFontWinSubstituteA
does give me some problem in this approach. charmap of both substitute
font and its subsets need to be updated. I ignored to update charmap
of subsets (because ccmap update is way too expensive), and system will
fallback to findFont to get it resolved. There might be a performance
side-impact because of this. So now I put am find subset operations into
nsFontWinA/nsFontWinSubstituteA. (I was planning to do this later. But as
you raise the question, I updated my patch. )
As for you second concern, there seems to be no perfect solution yet.
As suggested by cls, I borrowed existing practice and upate makefile.win.
Comment 25•25 years ago
|
||
I understand what you were aiming at regarding my first concern. It was that you
were not taking full advantage of the abstraction.
Now that you have added FindSubset(), I took notice that you have wisely added:
+nsFontSubset*
+nsFontWinSubstituteA::FindSubset(HDC aDC, PRUnichar aChar, nsFontMetricsWinA*
aFontMetrics)
+{
+ return mSubsets[0];
+}
To complete the trick, you can also add:
nsFontSubsetSubstitute::HasGlyph(aChar)
{
return PR_TRUE;
}
With that, you can then get rid of this special-casing in the higher code:
+ if (currFont == mSubstituteFont) {
+ //for substitute font, subset is not updated and can't be checked
+ if (!currFont->HasGlyph(*currChar))
+ break;
}
Comment 26•25 years ago
|
||
+nsFontSubset*
+nsFontWinA::FindSubset(HDC aDC, PRUnichar aChar, nsFontMetricsWinA*
aFontMetrics)
+{
+ for (PRUint16 i = 0; i < mSubsetsCount; i++) {
+ if (!mSubsets[i]->mCCMap)
+ mSubsets[i]->Load(aDC, aFontMetrics, this);
+ if (mSubsets[i]->HasGlyph(aChar))
+ return mSubsets[i];
+ }
+ return nsnull;
+}
>>>need to handle the case where the load fails (the 'while' version was
slightly faster).
| Reporter | ||
Comment 27•25 years ago
|
||
P2, this block a lot of work (new OpenType format 12, CJK Extension A, Extension
B, surrogate support, etc)
Priority: -- → P2
| Assignee | ||
Comment 28•25 years ago
|
||
| Assignee | ||
Updated•25 years ago
|
Attachment #54013 -
Attachment is obsolete: true
| Assignee | ||
Comment 29•25 years ago
|
||
rbs, I updated my patch as you suggested. A "break" in original code wasted me
almost a whole day. Please take one more look. Thanks.
(substituteFont handling in A-version is a pain, SystemSupportsChar should
prepare a charmap instead of enumerating each charset for each character.
I will file a bug later. Would you mind if I assign it to you, or you prefer me
to handle it? I am afraid my bug count is way too high.)
Comment 30•25 years ago
|
||
+static PRUint16* gUserDefinedCCMap;
>>>init: gUserDefinedCCMap = nsnull;
+nsFontSubset*
+nsFontWinA::FindSubset(HDC aDC, PRUnichar aChar, nsFontMetricsWinA*
aFontMetrics)
+{
+ nsFontSubset **subsetPtr = mSubsets;
+ nsFontSubset **endSubset = subsetPtr + mSubsetsCount;
+
+ while (subsetPtr < endSubset) {
+ if (!(*subsetPtr)->mCCMap)
+ if (!(*subsetPtr)->Load(aDC, aFontMetrics, this))
+ return nsnull;
>>>why return early here, maybe the next subset will succeed
>>>and will have the needed glyph
+ if ((*subsetPtr)->HasGlyph(aChar))
+ return (*subsetPtr);
+ subsetPtr++;
>>>nit: FYI, see the "lecture" in bug 78032 about developing an habit
>>>for ++subsetPtr -- although they often optimize to the same thing
+ }
+ return nsnull;
+}
+
=====================
@@ -4504,21 +4409,8 @@
+ if (font && font->HasGlyph(aChar)) {
+ return font->FindSubset(aDC, aChar, this);
>>>replacement for more robustness (keep looking if something
>>>goes wrong with that particular subset):
nsFontSubset* subset = FindSubset(aDC, aChar, this);
if (subset)
return subset;
}
}
=======================
@@ -4534,21 +4426,8 @@
+ if (font && font->HasGlyph(aChar)) {
+ return font->FindSubset(aDC, aChar, this);
>>>ditto here
=======================
@@ -4559,25 +4438,18 @@
{
for (int i = 0; i < sizeof(gBitToCharset); ++i) {
PRUint8 charset = gBitToCharset[i];
+ int j = gCharsetToIndex[charset];
+ if (!gCharsetInfo[j].mCCMap) {
+ if (charset == DEFAULT_CHARSET)
+ continue;
+ if (!HaveConverterFor(charset))
+ return 0;
>>>>The two inner |if| only depend on the 'charset', therefore they can be
>>>>factored out as follows:
for (int i = 0; i < sizeof(gBitToCharset); ++i) {
PRUint8 charset = gBitToCharset[i];
+ if (charset == DEFAULT_CHARSET)
+ continue;
+ if (!HaveConverterFor(charset))
+ return 0; //>>> BTW, why 'return' here, the previous code did 'continue'
+ int j = gCharsetToIndex[charset];
+ if (!gCharsetInfo[j].mCCMap) {
+ gCharsetInfo[j].mCCMap = gCharsetInfo[j].GenerateMap(&gCharsetInfo[j]);
+ if (!gCharsetInfo[j].mCCMap)
+ return 0;
}
+ if (CCMAP_HAS_CHAR(gCharsetInfo[j].mCCMap, aChar))
+ return 1;
}
=========
@@ -4627,19 +4499,9 @@
+ nsFontSubset* subset = font->FindSubset(aDC, c, this);
+ if (subset) {
+ return subset;
>>>ah, that's what I was mentioning above... it looks alright here.
==================
@@ -4659,39 +4531,33 @@
+ nsFontSubset* substituteSubset =
((nsFontWinA*)mSubstituteFont)->mSubsets[0];
+ ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(aChar);
return substituteSubset;
>>>nit: maybe you could get rid of the temporary variable and just
>>>return ((nsFontWinA*)mSubstituteFont)->mSubsets[0]
==================
@@ -4779,65 +4638,40 @@
+ for (; j < i-1; ++j) {
+ // NOTE: we are overwriting variables here (we now *know* that we
+ // will break out of the bigger outer loop after the callback...)
>>>Now that you added FindSubset(), these comments are outdated and can go away
>>>(and the infamous "break" mentioned there became obsolete too, as you saw ;-)
Nice job.
Comment 31•25 years ago
|
||
>I will file a bug later. Would you mind if I assign it to you, or you prefer
>me to handle it? I am afraid my bug count is way too high.)
I have filed bug 105592, targeted at Future for the record.
| Assignee | ||
Comment 32•25 years ago
|
||
Comment 33•25 years ago
|
||
I still see
+ if (!HaveConverterFor(charset))
+ return 0; //>>> BTW, why 'return' here, the previous code did 'continue'
and cases of:
+ if (font && font->HasGlyph(aChar)) {
+ return font->FindSubset(aDC, aChar, this);
}
which I suggested to replace with:
subset = font->FindSubset(aDC, aChar, this);
if (subset)
return subset;
BTW, for speedy reviews, it helps to point out what you didn't fix and why.
This way, I can quickly tell whether it is on purpose or whether it is just
an omission.
The reason why I am wondering about the early return is because one may
wish to keep trying when going through the loop of the font-family list,
"font-family: font1, font2, font3" :
while (mFontsIndex < mFonts.Count()) {
[...]
+ if (font && font->HasGlyph(aChar)) {
+ return font->FindSubset(aDC, aChar, this);
}
[...]
}
| Assignee | ||
Comment 34•25 years ago
|
||
| Assignee | ||
Comment 35•25 years ago
|
||
I updated my patch once again. I missed the "HaveConverter" line, that is a
mistake. The instance of "FindSubset" left there is intentional. That is because
that call is not within a loop.
| Assignee | ||
Updated•25 years ago
|
Attachment #54177 -
Attachment is obsolete: true
| Assignee | ||
Updated•25 years ago
|
Attachment #54218 -
Attachment is obsolete: true
Comment 36•25 years ago
|
||
Comment on attachment 54303 [details] [diff] [review]
patch 7.3
r=rbs
Attachment #54303 -
Flags: review+
Comment 37•25 years ago
|
||
Is this being done on a nsCompressedCharMap (C++) object?
> ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(c);
In general, it is not valid to turn on a bit in a PRUint16* compressed char map
since the map is not fully populated.
Comment 38•25 years ago
|
||
As an option for faster map comparison:
I had considered adding 8 bytes to each map that
contained the char count and a simple checksum of the chars. Comparing
these would quickly eliminate most non matching maps. Somethine like this:
// offsets to the empty mid and empty page
- #define CCMAP_EMPTY_MID CCMAP_NUM_UPPER_POINTERS
+ #define CCMAP_COUNT CCMAP_NUM_UPPER_POINTERS
+ #define CCMAP_CKSUM CCMAP_COUNT + 4
+ #define CCMAP_EMPTY_MID CCMAP_CKSUM + 4
Then increment(decrement) the count as chars are added(subtracted) and
add(subtract) the new char to(from) the checksum.
Comment 39•25 years ago
|
||
> Is this being done on a nsCompressedCharMap (C++) object?
No.
> > ((nsFontWinSubstitute*)mSubstituteFont)->SetRepresentable(c);
>
>In general, it is not valid to turn on a bit in a PRUint16* compressed char map
>since the map is not fully populated.
Not a problem here since the substitute font uses a "normal" map.
| Assignee | ||
Comment 40•25 years ago
|
||
I suggest to leave further optimization of charmap operation to other bugs.
| Assignee | ||
Comment 41•25 years ago
|
||
Marc, Could you sr this bug?
Comment 42•25 years ago
|
||
Comment on attachment 54303 [details] [diff] [review]
patch 7.3
rs=attinasi
Attachment #54303 -
Flags: superreview+
| Assignee | ||
Comment 43•25 years ago
|
||
fix checked in.
Status: ASSIGNED → RESOLVED
Closed: 25 years ago
Resolution: --- → FIXED
Comment 44•25 years ago
|
||
I updated one of my trees to catch up with the tip and your changes. I am seeing
something strange at: http://www.joins.com/ (a Korean site)
Not sure if it is due to something strange in my tree. In of of my older trees
that are not yet updated to the tip, the page renders fine. Do you see any
problem at that site?
Comment 45•25 years ago
|
||
False alarm. It renders fine after another launch. Maybe something wasn't
registered properly at my first launch after the build completed.
You need to log in
before you can comment on or make changes to this bug.
Description
•